include/svx/svdmodel.hxx | 4 + sc/source/ui/docshell/docsh.cxx | 2 sd/source/ui/docshell/docshel4.cxx | 1 svx/qa/unit/data/tdf148000_EOLinCurvedText.pptx |binary svx/qa/unit/data/tdf148000_EOLinCurvedText_Legacy.odp |binary svx/qa/unit/data/tdf148000_EOLinCurvedText_New.odp |binary svx/qa/unit/svdraw.cxx | 42 +++++++++++ svx/source/customshapes/EnhancedCustomShapeFontWork.cxx | 57 ++++++++++++---- svx/source/svdraw/svdmodel.cxx | 42 +++++++++++ sw/source/uibase/app/docshini.cxx | 10 +- 10 files changed, 142 insertions(+), 16 deletions(-)
New commits: commit f9d6dd788e82a1964dab9cc0d0436c8c54b775c0 Author: Attila Szűcs <attila.sz...@collabora.com> AuthorDate: Fri Jan 13 04:49:33 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Jan 20 07:56:29 2023 +0000 tdf#148000 impress: Handle linebreaks on fontwork. Split text lines in a paragraph, right before polygons are created for rendering, so eol will brake line in fontwork just like eop. Change-Id: Ie9e6764f9f91c2e19afd43dc9a212bd18c41c99d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145425 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/svx/svdmodel.hxx b/include/svx/svdmodel.hxx index 7c23b5a24712..b5d93fa53eb7 100644 --- a/include/svx/svdmodel.hxx +++ b/include/svx/svdmodel.hxx @@ -575,6 +575,10 @@ public: void SetAnchoredTextOverflowLegacy(bool bEnabled); bool IsAnchoredTextOverflowLegacy() const; + // tdf#148000 compatibility flag + void SetLegacySingleLineFontwork(bool bEnabled); + bool IsLegacySingleLineFontwork() const; + void ReformatAllTextObjects(); std::unique_ptr<SdrOutliner> createOutliner( OutlinerMode nOutlinerMode ); diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 071c2530f61b..1f58bf43f1b7 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -589,6 +589,8 @@ bool ScDocShell::Load( SfxMedium& rMedium ) { if (m_pDocument->GetDrawLayer()) m_pDocument->GetDrawLayer()->SetAnchoredTextOverflowLegacy(true); + if (m_pDocument->GetDrawLayer()) + m_pDocument->GetDrawLayer()->SetLegacySingleLineFontwork(true); //for tdf#148000 } GetUndoManager()->Clear(); diff --git a/sd/source/ui/docshell/docshel4.cxx b/sd/source/ui/docshell/docshel4.cxx index 99d6890fe1f0..4df8aee97a4a 100644 --- a/sd/source/ui/docshell/docshel4.cxx +++ b/sd/source/ui/docshell/docshel4.cxx @@ -269,6 +269,7 @@ bool DrawDocShell::Load( SfxMedium& rMedium ) if (IsOwnStorageFormat(rMedium)) { mpDoc->SetAnchoredTextOverflowLegacy(true); + mpDoc->SetLegacySingleLineFontwork(true); //for tdf#148000 } bool bRet = false; diff --git a/svx/qa/unit/data/tdf148000_EOLinCurvedText.pptx b/svx/qa/unit/data/tdf148000_EOLinCurvedText.pptx new file mode 100644 index 000000000000..137fc816697a Binary files /dev/null and b/svx/qa/unit/data/tdf148000_EOLinCurvedText.pptx differ diff --git a/svx/qa/unit/data/tdf148000_EOLinCurvedText_Legacy.odp b/svx/qa/unit/data/tdf148000_EOLinCurvedText_Legacy.odp new file mode 100644 index 000000000000..13e7cc4e5c8a Binary files /dev/null and b/svx/qa/unit/data/tdf148000_EOLinCurvedText_Legacy.odp differ diff --git a/svx/qa/unit/data/tdf148000_EOLinCurvedText_New.odp b/svx/qa/unit/data/tdf148000_EOLinCurvedText_New.odp new file mode 100644 index 000000000000..7ebdb9431b72 Binary files /dev/null and b/svx/qa/unit/data/tdf148000_EOLinCurvedText_New.odp differ diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx index c2a7f244b8ab..7bf1ceb9d4a1 100644 --- a/svx/qa/unit/svdraw.cxx +++ b/svx/qa/unit/svdraw.cxx @@ -382,6 +382,48 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testFontWorks) "32"); } +CPPUNIT_TEST_FIXTURE(SvdrawTest, testTdf148000_EOLinCurvedText) +{ + std::vector<OUString> aFilenames + = { u"tdf148000_EOLinCurvedText.pptx", u"tdf148000_EOLinCurvedText_New.odp", + u"tdf148000_EOLinCurvedText_Legacy.odp" }; + + for (int i = 0; i < 3; i++) + { + loadFromURL(aFilenames[i]); + + SdrPage* pSdrPage = getFirstDrawPageWithAssert(); + + xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage); + + OString aBasePath + = "/primitive2D/objectinfo[4]/unhandled/unhandled/polypolygoncolor/polypolygon/"; + + // The text is: "O" + eop + "O" + eol + "O" + // It should be displayed as 3 line of text. (1 "O" letter in every line) + sal_Int32 nY1 = getXPath(pXmlDoc, aBasePath + "polygon[1]/point[1]", "y").toInt32(); + sal_Int32 nY2 = getXPath(pXmlDoc, aBasePath + "polygon[3]/point[1]", "y").toInt32(); + sal_Int32 nY3 = getXPath(pXmlDoc, aBasePath + "polygon[5]/point[1]", "y").toInt32(); + + sal_Int32 nDiff21 = nY2 - nY1; + sal_Int32 nDiff32 = nY3 - nY2; + + // the 2. "O" must be positioned much lower as the 1. "O". (the eop break the line) + CPPUNIT_ASSERT_GREATER(sal_Int32(300), nDiff21); + if (i < 2) + { + // the 3. "O" must be positioned even lower with 1 line. (the eol must break the line as well) + CPPUNIT_ASSERT_LESS(sal_Int32(50), abs(nDiff32 - nDiff21)); + } + else + { + // In legacy mode, the 3. "O" must be positioned about the same high as the 2. "O" + // the eol not break the line. + CPPUNIT_ASSERT_LESS(sal_Int32(50), nDiff32); + } + } +} + CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMetal) { loadFromURL(u"tdf140321_metal.odp"); diff --git a/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx index e8e3bd026cd1..672cd28fbc8e 100644 --- a/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx +++ b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx @@ -36,6 +36,7 @@ #include <editeng/charscaleitem.hxx> #include <svx/svdoashp.hxx> #include <svx/sdshitm.hxx> +#include <svx/svdmodel.hxx> #include <editeng/outlobj.hxx> #include <editeng/editobj.hxx> #include <o3tl/numeric.hxx> @@ -50,6 +51,7 @@ #include <sal/log.hxx> #include <rtl/math.hxx> #include <unotools/configmgr.hxx> +#include <comphelper/string.hxx> using namespace com::sun::star; using namespace com::sun::star::uno; @@ -116,27 +118,58 @@ static bool InitializeFontWorkData( if ( pParaObj ) { const EditTextObject& rTextObj = pParaObj->GetTextObject(); - sal_Int32 nParagraphsLeft = rTextObj.GetParagraphCount(); + sal_Int32 nParagraphsCount = rTextObj.GetParagraphCount(); + + // Collect all the lines from all paragraphs + std::vector<int> aLineParaID; // which para this line is in + std::vector<int> aLineStart; // where this line start in that para + std::vector<int> aLineLength; + std::vector<OUString> aParaText; + for (sal_Int32 nPara = 0; nPara < nParagraphsCount; ++nPara) + { + aParaText.push_back(rTextObj.GetText(nPara)); + sal_Int32 nPos = 0; + sal_Int32 nPrevPos = 0; + do + { + // search line break. + if (!rSdrObjCustomShape.getSdrModelFromSdrObject().IsLegacySingleLineFontwork()) + nPos = aParaText[nPara].indexOf(sal_Unicode(u'\1'), nPrevPos); + else + nPos = -1; // tdf#148000: ignore line breaks in legacy fontworks + + aLineParaID.push_back(nPara); + aLineStart.push_back(nPrevPos); + aLineLength.push_back((nPos >= 0 ? nPos : aParaText[nPara].getLength()) + - nPrevPos); + nPrevPos = nPos + 1; + } while (nPos >= 0); + } + + sal_Int32 nLinesLeft = aLineParaID.size(); - rFWData.nMaxParagraphsPerTextArea = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1; - sal_Int32 j = 0; - while( nParagraphsLeft && nTextAreaCount ) + rFWData.nMaxParagraphsPerTextArea = ((nLinesLeft - 1) / nTextAreaCount) + 1; + sal_Int32 nLine = 0; + while (nLinesLeft && nTextAreaCount) { FWTextArea aTextArea; - sal_Int32 i, nParagraphs = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1; - for ( i = 0; i < nParagraphs; ++i, ++j ) + sal_Int32 nLinesInPara = ((nLinesLeft - 1) / nTextAreaCount) + 1; + for (sal_Int32 i = 0; i < nLinesInPara; ++i, ++nLine) { FWParagraphData aParagraphData; - aParagraphData.aString = rTextObj.GetText( j ); + aParagraphData.aString = aParaText[aLineParaID[nLine]].subView( + aLineStart[nLine], aLineLength[nLine]); - const SfxItemSet& rParaSet = rTextObj.GetParaAttribs( j ); // retrieving some paragraph attributes - aParagraphData.nFrameDirection = rParaSet.Get( EE_PARA_WRITINGDIR ).GetValue(); - aTextArea.vParagraphs.push_back( aParagraphData ); + // retrieving some paragraph attributes + const SfxItemSet& rParaSet = rTextObj.GetParaAttribs(aLineParaID[nLine]); + aParagraphData.nFrameDirection = rParaSet.Get(EE_PARA_WRITINGDIR).GetValue(); + aTextArea.vParagraphs.push_back(aParagraphData); } - rFWData.vTextAreas.push_back( aTextArea ); - nParagraphsLeft -= nParagraphs; + rFWData.vTextAreas.push_back(aTextArea); + nLinesLeft -= nLinesInPara; nTextAreaCount--; } + bNoErr = true; } } diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx index 3feb1ae0669b..bc86671c9437 100644 --- a/svx/source/svdraw/svdmodel.cxx +++ b/svx/source/svdraw/svdmodel.cxx @@ -72,6 +72,9 @@ #include <comphelper/diagnose_ex.hxx> #include <tools/UnitConversion.hxx> #include <svx/ColorSets.hxx> +#include <svx/svditer.hxx> +#include <svx/svdoashp.hxx> + using namespace ::com::sun::star; @@ -80,12 +83,14 @@ struct SdrModelImpl SfxUndoManager* mpUndoManager; SdrUndoFactory* mpUndoFactory; bool mbAnchoredTextOverflowLegacy; // tdf#99729 compatibility flag + bool mbLegacySingleLineFontwork; // tdf#148000 compatibility flag std::unique_ptr<svx::Theme> mpTheme; SdrModelImpl() : mpUndoManager(nullptr) , mpUndoFactory(nullptr) , mbAnchoredTextOverflowLegacy(false) + , mbLegacySingleLineFontwork(false) {} }; @@ -1718,6 +1723,16 @@ bool SdrModel::IsAnchoredTextOverflowLegacy() const return mpImpl->mbAnchoredTextOverflowLegacy; } +void SdrModel::SetLegacySingleLineFontwork(bool bEnabled) +{ + mpImpl->mbLegacySingleLineFontwork = bEnabled; +} + +bool SdrModel::IsLegacySingleLineFontwork() const +{ + return mpImpl->mbLegacySingleLineFontwork; +} + void SdrModel::ReformatAllTextObjects() { ImpReformatAllTextObjects(); @@ -1761,6 +1776,32 @@ void SdrModel::ReadUserDataSequenceValue(const beans::PropertyValue* pValue) mpImpl->mbAnchoredTextOverflowLegacy = bBool; } } + else if (pValue->Name == "LegacySingleLineFontwork") + { + bool bBool = false; + if (pValue->Value >>= bBool) + { + mpImpl->mbLegacySingleLineFontwork = bBool; + // tdf#148000 hack: reset all CustomShape geometry as they may depend on this property + // Ideally this ReadUserDataSequenceValue should be called before geometry creation + // Once the calling order will be fixed, this hack will not be needed. + for (size_t i = 0; i < maPages.size(); ++i) + { + if (const SdrPage* pPage = maPages[i].get()) + { + SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups); + while (aIter.IsMore()) + { + SdrObject* pTempObj = aIter.Next(); + if (SdrObjCustomShape* pShape = dynamic_cast<SdrObjCustomShape*>(pTempObj)) + { + pShape->InvalidateRenderGeometry(); + } + } + } + } + } + } } template <typename T> @@ -1773,6 +1814,7 @@ void SdrModel::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rValu { std::vector< std::pair< OUString, uno::Any > > aUserData; addPair(aUserData, "AnchoredTextOverflowLegacy", IsAnchoredTextOverflowLegacy()); + addPair(aUserData, "LegacySingleLineFontwork", IsLegacySingleLineFontwork()); const sal_Int32 nOldLength = rValues.getLength(); rValues.realloc(nOldLength + aUserData.size()); diff --git a/sw/source/uibase/app/docshini.cxx b/sw/source/uibase/app/docshini.cxx index c5432a98af29..72e630ac02b2 100644 --- a/sw/source/uibase/app/docshini.cxx +++ b/sw/source/uibase/app/docshini.cxx @@ -476,10 +476,12 @@ bool SwDocShell::Load( SfxMedium& rMedium ) // (if required, they will be overridden later when settings will be read) if (IsOwnStorageFormat(rMedium)) { - // legacy processing for tdf#99729 - if (m_xDoc->getIDocumentDrawModelAccess().GetDrawModel()) - m_xDoc->getIDocumentDrawModelAccess().GetDrawModel()->SetAnchoredTextOverflowLegacy( - true); + SwDrawModel* pDrawModel = m_xDoc->getIDocumentDrawModelAccess().GetDrawModel(); + if (pDrawModel) + { + pDrawModel->SetAnchoredTextOverflowLegacy(true); // legacy processing for tdf#99729 + pDrawModel->SetLegacySingleLineFontwork(true); // legacy processing for tdf#148000 + } } // Loading