vcl/CppunitTest_vcl_textlayout.mk |    1 
 vcl/inc/textlayout.hxx            |   10 ++---
 vcl/qa/cppunit/textlayout.cxx     |   64 +++++++++++++++++++++++++++++++++++---
 vcl/source/text/textlayout.cxx    |   61 +++++++++++++++++-------------------
 4 files changed, 96 insertions(+), 40 deletions(-)

New commits:
commit 938d3b35b83093de4e310d32de5137f6bdbcf22b
Author:     Chris Sherlock <chris.sherloc...@gmail.com>
AuthorDate: Sun Oct 1 18:08:49 2023 +1100
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Thu Dec 28 02:33:50 2023 +0100

    vcl: test BreakLinesWithIterator with hyphens
    
    Change-Id: Ied5e688b9eec19c2f1b3d1289cc4a6605703c3e4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157904
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/vcl/CppunitTest_vcl_textlayout.mk 
b/vcl/CppunitTest_vcl_textlayout.mk
index d7ac49a9e6df..57d5177f2a19 100644
--- a/vcl/CppunitTest_vcl_textlayout.mk
+++ b/vcl/CppunitTest_vcl_textlayout.mk
@@ -55,6 +55,7 @@ $(eval $(call gb_CppunitTest_use_components,vcl_textlayout,\
        configmgr/source/configmgr \
        i18npool/util/i18npool \
        ucb/source/core/ucb1 \
+       linguistic/source/lng \
 ))
 
 $(eval $(call gb_CppunitTest_use_configuration,vcl_textlayout))
diff --git a/vcl/inc/textlayout.hxx b/vcl/inc/textlayout.hxx
index 58f3bb33469b..d05259475d18 100644
--- a/vcl/inc/textlayout.hxx
+++ b/vcl/inc/textlayout.hxx
@@ -52,14 +52,14 @@ namespace vcl
     public:
         OUString GetEllipsisString(OUString const& rOrigStr, tools::Long 
nMaxWidth, DrawTextFlags nStyle);
 
-        sal_Int32 BreakLinesWithIterator(const tools::Long nWidth, OUString 
const& rStr,
+        std::tuple<sal_Int32, sal_Int32> BreakLines(const tools::Long nWidth, 
OUString const& rStr,
                         css::uno::Reference< css::linguistic2::XHyphenator > 
const& xHyph,
-                        css::uno::Reference<css::i18n::XBreakIterator> const& 
xBI,
-                        const bool bHyphenate,
+                        css::uno::Reference<css::i18n::XBreakIterator>& xBI,
+                        const bool bHyphenate, const tools::Long 
nOrigLineWidth,
                         const sal_Int32 nPos, const sal_Int32 nLen);
 
-        sal_Int32 BreakLinesSimple(const tools::Long nWidth, OUString const& 
rStr,
-                                  const sal_Int32 nPos, sal_Int32 nBreakPos, 
tools::Long& nLineWidth);
+        std::tuple<sal_Int32, sal_Int32> BreakLinesSimple(const tools::Long 
nWidth, OUString const& rStr,
+                                  const sal_Int32 nPos, sal_Int32 nBreakPos, 
const tools::Long nOrigLineWidth);
 
         tools::Long GetTextLines(tools::Rectangle const& rRect, const 
tools::Long nTextHeight,
                                  ImplMultiTextLineInfo& rLineInfo,
diff --git a/vcl/qa/cppunit/textlayout.cxx b/vcl/qa/cppunit/textlayout.cxx
index 147826f19842..3ace6a8b836d 100644
--- a/vcl/qa/cppunit/textlayout.cxx
+++ b/vcl/qa/cppunit/textlayout.cxx
@@ -12,6 +12,8 @@
 
 #include <test/bootstrapfixture.hxx>
 
+#include <comphelper/processfactory.hxx>
+
 #include <vcl/unohelp.hxx>
 #include <vcl/virdev.hxx>
 
@@ -28,7 +30,7 @@ public:
 
 #if HAVE_MORE_FONTS
 
-CPPUNIT_TEST_FIXTURE(VclTextLayoutTest, 
testBreakLinesWithIterator_invalid_softbreak)
+CPPUNIT_TEST_FIXTURE(VclTextLayoutTest, testBreakLines_invalid_softbreak)
 {
     ScopedVclPtr<VirtualDevice> device = 
VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
     device->SetOutputSizePixel(Size(1000, 1000));
@@ -46,9 +48,63 @@ CPPUNIT_TEST_FIXTURE(VclTextLayoutTest, 
testBreakLinesWithIterator_invalid_softb
 
     const auto nTextLen = 13;
 
-    CPPUNIT_ASSERT_EQUAL(
-        static_cast<sal_Int32>(13),
-        aTextLayout.BreakLinesWithIterator(nTextWidth, sTestStr, xHyph, xBI, 
false, nTextLen, 15));
+    auto[nBreakPos, nLineWidth]
+        = aTextLayout.BreakLines(nTextWidth, sTestStr, xHyph, xBI, false, 
nTextWidth, nTextLen, 15);
+
+    const sal_Int32 nExpectedBreakPos = 13;
+    CPPUNIT_ASSERT_EQUAL(nExpectedBreakPos, nBreakPos);
+}
+
+CPPUNIT_TEST_FIXTURE(VclTextLayoutTest, testBreakLines_hyphens)
+{
+    ScopedVclPtr<VirtualDevice> device = 
VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
+    device->SetOutputSizePixel(Size(1000, 1000));
+    device->SetFont(vcl::Font("DejaVu Sans", "Book", Size(0, 11)));
+
+    vcl::DefaultTextLayout aTextLayout(*device);
+
+    const OUString sTestStr = u"textline text-moretext"_ustr;
+    const auto nTextWidth = device->GetTextWidth("textline text-moretex");
+
+    css::uno::Reference<css::uno::XComponentContext> xContext(
+        comphelper::getProcessComponentContext());
+    css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLinguMgr
+        = css::linguistic2::LinguServiceManager::create(xContext);
+
+    css::uno::Reference<css::linguistic2::XHyphenator> xHyph = 
xLinguMgr->getHyphenator();
+    css::uno::Reference<css::i18n::XBreakIterator> xBI = 
vcl::unohelper::CreateBreakIterator();
+
+    auto[nBreakPos, nLineWidth]
+        = aTextLayout.BreakLines(nTextWidth, sTestStr, xHyph, xBI, true, 
nTextWidth, 13, 12);
+
+    const sal_Int32 nExpectedBreakPos = 13;
+    CPPUNIT_ASSERT_EQUAL(nExpectedBreakPos, nBreakPos);
+}
+
+CPPUNIT_TEST_FIXTURE(VclTextLayoutTest, 
testBreakLines_hyphen_word_under_two_chars)
+{
+    ScopedVclPtr<VirtualDevice> device = 
VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
+    device->SetOutputSizePixel(Size(1000, 1000));
+    device->SetFont(vcl::Font("DejaVu Sans", "Book", Size(0, 11)));
+
+    vcl::DefaultTextLayout aTextLayout(*device);
+
+    const OUString sTestStr = u"textline text-moretext"_ustr;
+    const auto nTextWidth = device->GetTextWidth("te-moretex");
+
+    css::uno::Reference<css::uno::XComponentContext> xContext(
+        comphelper::getProcessComponentContext());
+    css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLinguMgr
+        = css::linguistic2::LinguServiceManager::create(xContext);
+
+    css::uno::Reference<css::linguistic2::XHyphenator> xHyph = 
xLinguMgr->getHyphenator();
+    css::uno::Reference<css::i18n::XBreakIterator> xBI = 
vcl::unohelper::CreateBreakIterator();
+
+    auto[nBreakPos, nLineWidth]
+        = aTextLayout.BreakLines(nTextWidth, sTestStr, xHyph, xBI, true, 
nTextWidth, 2, 10);
+
+    const sal_Int32 nExpectedBreakPos = 2;
+    CPPUNIT_ASSERT_EQUAL(nExpectedBreakPos, nBreakPos);
 }
 
 #endif
diff --git a/vcl/source/text/textlayout.cxx b/vcl/source/text/textlayout.cxx
index 095c087d5377..e90c56b6355a 100644
--- a/vcl/source/text/textlayout.cxx
+++ b/vcl/source/text/textlayout.cxx
@@ -218,12 +218,18 @@ namespace vcl
         return aStr;
     }
 
-    sal_Int32 TextLayoutCommon::BreakLinesWithIterator(const tools::Long 
nWidth, OUString const& rStr,
+    std::tuple<sal_Int32, sal_Int32> TextLayoutCommon::BreakLines(const 
tools::Long nWidth, OUString const& rStr,
                         css::uno::Reference< css::linguistic2::XHyphenator > 
const& xHyph,
-                        css::uno::Reference<css::i18n::XBreakIterator> const& 
xBI,
-                        const bool bHyphenate,
+                        css::uno::Reference<css::i18n::XBreakIterator>& xBI,
+                        const bool bHyphenate, const tools::Long 
nOrigLineWidth,
                         const sal_Int32 nPos, const sal_Int32 nLen)
     {
+        if (!xBI.is())
+            xBI = vcl::unohelper::CreateBreakIterator();
+
+        if (!xBI.is())
+            return BreakLinesSimple(nWidth, rStr, nPos, nLen, nOrigLineWidth);
+
         const css::lang::Locale& 
rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
 
         sal_Int32 nSoftBreak = GetTextBreak(rStr, nWidth, nPos, nLen - nPos);
@@ -241,16 +247,14 @@ namespace vcl
         if (nBreakPos <= nPos)
             nBreakPos = nSoftBreak;
 
-        if (!bHyphenate)
-            return nBreakPos;
+        if (!bHyphenate || !xHyph.is())
+            return { nBreakPos, GetTextWidth(rStr, nPos, nBreakPos - nPos) };
 
         // Whether hyphen or not: Put the word after the hyphen through
         // the word boundary.
 
         // We run into a problem if the doc is so narrow, that a word
         // is broken into more than two lines ...
-        if ( !xHyph.is() )
-            return nBreakPos;
 
         css::i18n::Boundary aBoundary = xBI->getWordBoundary( rStr, nBreakPos, 
rDefLocale, css::i18n::WordType::DICTIONARY_WORD, true );
         sal_Int32 nWordStart = nPos;
@@ -258,27 +262,28 @@ namespace vcl
         SAL_WARN_IF(nWordEnd <= nWordStart, "vcl", "Start >= End?");
 
         sal_Int32 nWordLen = nWordEnd - nWordStart;
-        if ( ( nWordEnd < nSoftBreak ) || ( nWordLen <= 3 ) )
-            return nBreakPos;
+        if ((nWordEnd < nSoftBreak) || (nWordLen <= 3))
+            return { nBreakPos, GetTextWidth(rStr, nPos, nBreakPos - nPos) };
 
         OUString aWord = rStr.copy( nWordStart, nWordLen );
         sal_Int32 nMinTrail = nWordEnd-nSoftBreak+1;  //+1: Before the "broken 
off" char
         css::uno::Reference< css::linguistic2::XHyphenatedWord > xHyphWord;
         if (xHyph.is())
             xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.getLength() 
- nMinTrail, css::uno::Sequence< css::beans::PropertyValue >() );
+
         if (!xHyphWord.is())
-            return nBreakPos;
+            return { nBreakPos, GetTextWidth(rStr, nPos, nBreakPos - nPos) };
 
         bool bAlternate = xHyphWord->isAlternativeSpelling();
         sal_Int32 _nWordLen = 1 + xHyphWord->getHyphenPos();
 
-        if ( ( _nWordLen < 2 ) || ( (nWordStart+_nWordLen) < 2 ) )
-            return nBreakPos;
+        if ((_nWordLen < 2 ) || ( (nWordStart + _nWordLen) < 2))
+            return { nBreakPos, GetTextWidth(rStr, nPos, nBreakPos - nPos) };
 
-        if ( bAlternate )
+        if (bAlternate)
         {
             nBreakPos = nWordStart + _nWordLen;
-            return nBreakPos;
+            return { nBreakPos, GetTextWidth(rStr, nPos, nBreakPos - nPos) };
         }
 
         OUString aAlt( xHyphWord->getHyphenatedWord() );
@@ -329,14 +334,18 @@ namespace vcl
         nBreakPos = nWordStart + nTxtStart;
         if ( cAlternateReplChar )
             nBreakPos++;
-        return nBreakPos;
+
+        return { nBreakPos, GetTextWidth(rStr, nPos, nBreakPos - nPos) };
     }
 
-    sal_Int32 TextLayoutCommon::BreakLinesSimple(const tools::Long nWidth, 
OUString const& rStr,
-                                                 const sal_Int32 nPos, 
sal_Int32 nBreakPos, tools::Long& nLineWidth)
+    std::tuple<sal_Int32, sal_Int32> TextLayoutCommon::BreakLinesSimple(const 
tools::Long nWidth, OUString const& rStr,
+                                                 const sal_Int32 nPos, const 
sal_Int32 nLen, const tools::Long nOrigLineWidth)
     {
+        sal_Int32 nBreakPos = nLen;
+        tools::Long nLineWidth = nOrigLineWidth;
         sal_Int32 nSpacePos = rStr.getLength();
         tools::Long nW = 0;
+
         do
         {
             nSpacePos = rStr.lastIndexOf( ' ', nSpacePos );
@@ -355,7 +364,8 @@ namespace vcl
             if( nBreakPos < rStr.getLength()-1 )
                 nBreakPos++;
         }
-        return nBreakPos;
+
+        return { nBreakPos, nLineWidth };
     }
 
     namespace
@@ -413,20 +423,9 @@ namespace vcl
             sal_Int32 nBreakPos = lcl_GetEndOfLine(rStr, nPos, nLen);
             tools::Long nLineWidth = GetTextWidth(rStr, nPos, nBreakPos-nPos);
 
+
             if (lcl_ShouldBreakWord(nLineWidth, nWidth, nStyle))
-            {
-                if (!xBI.is())
-                    xBI = vcl::unohelper::CreateBreakIterator();
-
-                if (xBI.is())
-                {
-                    nBreakPos = BreakLinesWithIterator(nWidth, rStr, xHyph, 
xBI, bHyphenate, nPos, nBreakPos);
-                    nLineWidth = GetTextWidth(rStr, nPos, nBreakPos - nPos);
-                }
-                else
-                    // fallback to something really simple
-                    nBreakPos = BreakLinesSimple(nWidth, rStr, nPos, 
nBreakPos, nLineWidth);
-            }
+                std::tie(nBreakPos, nLineWidth) = BreakLines(nWidth, rStr, 
xHyph, xBI, bHyphenate, nLineWidth, nPos, nBreakPos);
 
             if ( nLineWidth > nMaxLineWidth )
                 nMaxLineWidth = nLineWidth;

Reply via email to