include/vcl/outdev.hxx     |   17 ++
 vcl/source/outdev/text.cxx |  358 +++++++++++++++++++++++----------------------
 2 files changed, 202 insertions(+), 173 deletions(-)

New commits:
commit 4fc1b3fb659be916167518b49ffe8193e9033f30
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Tue Oct 26 09:15:17 2021 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Tue Oct 26 10:31:44 2021 +0200

    flatten ImplGetTextLines
    
    Change-Id: Iefbbcb186b2811748abf49546351a2c68e8af462
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124155
    Tested-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 6f85e0d51fef..ce988ab60719 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -130,6 +130,12 @@ namespace com::sun::star::rendering {
     class XCanvas;
     class XSpriteCanvas;
 }
+namespace com::sun::star::linguistic2 {
+    class XHyphenator;
+}
+namespace com::sun::star::i18n {
+    class XBreakIterator;
+}
 
 #if defined UNX
 #define GLYPH_FONT_HEIGHT   128
@@ -1076,7 +1082,16 @@ protected:
     SAL_DLLPRIVATE void         ImplInitTextLineSize();
     SAL_DLLPRIVATE void         ImplInitAboveTextLineSize();
     static
-    SAL_DLLPRIVATE tools::Long         ImplGetTextLines( 
ImplMultiTextLineInfo& rLineInfo, tools::Long nWidth, const OUString& rStr, 
DrawTextFlags nStyle, const vcl::ITextLayout& _rLayout );
+    SAL_DLLPRIVATE tools::Long  ImplGetTextLines( ImplMultiTextLineInfo& 
rLineInfo, tools::Long nWidth, const OUString& rStr, DrawTextFlags nStyle, 
const vcl::ITextLayout& _rLayout );
+    static
+    SAL_DLLPRIVATE sal_Int32    ImplBreakLinesWithIterator(const tools::Long 
nWidth, const OUString& rStr, const vcl::ITextLayout& _rLayout,
+                                    const 
css::uno::Reference<css::linguistic2::XHyphenator>& xHyph,
+                                    const 
css::uno::Reference<css::i18n::XBreakIterator>& xBI,
+                                    const bool bHyphenate,
+                                    const sal_Int32 nPos, sal_Int32 nBreakPos);
+    static
+    SAL_DLLPRIVATE sal_Int32    ImplBreakLinesSimple( const tools::Long 
nWidth, const OUString& rStr,
+                                    const vcl::ITextLayout& _rLayout, const 
sal_Int32 nPos, sal_Int32 nBreakPos, tools::Long& nLineWidth );
     SAL_DLLPRIVATE float        approximate_char_width() const;
 
     virtual bool shouldDrawWavePixelAsRect(tools::Long nLineWidth) const;
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 0b37b8fc743f..58e0b0e6a8b9 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -487,191 +487,62 @@ tools::Long OutputDevice::ImplGetTextLines( 
ImplMultiTextLineInfo& rLineInfo,
     if ( nWidth <= 0 )
         nWidth = 1;
 
-    tools::Long nMaxLineWidth  = 0;
     rLineInfo.Clear();
-    if (!rStr.isEmpty())
-    {
-        const bool bHyphenate = (nStyle & DrawTextFlags::WordBreakHyphenation) 
== DrawTextFlags::WordBreakHyphenation;
-        css::uno::Reference< css::linguistic2::XHyphenator > xHyph;
-        if (bHyphenate)
-        {
-            // get service provider
-            css::uno::Reference<css::uno::XComponentContext> 
xContext(comphelper::getProcessComponentContext());
-            css::uno::Reference<css::linguistic2::XLinguServiceManager2> 
xLinguMgr = css::linguistic2::LinguServiceManager::create(xContext);
-            xHyph = xLinguMgr->getHyphenator();
-        }
-
-        css::uno::Reference<css::i18n::XBreakIterator> xBI;
-        sal_Int32 nPos = 0;
-        sal_Int32 nLen = rStr.getLength();
-        while ( nPos < nLen )
-        {
-            sal_Int32 nBreakPos = nPos;
-
-            while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( 
rStr[ nBreakPos ] != '\n' ) )
-                nBreakPos++;
-
-            tools::Long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, 
nBreakPos-nPos );
-            if ( ( nLineWidth > nWidth ) && ( nStyle & 
DrawTextFlags::WordBreak ) )
-            {
-                if ( !xBI.is() )
-                    xBI = vcl::unohelper::CreateBreakIterator();
+    if (rStr.isEmpty())
+        return 0;
 
-                if ( xBI.is() )
-                {
-                    const css::lang::Locale& 
rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
-                    sal_Int32 nSoftBreak = _rLayout.GetTextBreak( rStr, 
nWidth, nPos, nBreakPos - nPos );
-                    if (nSoftBreak == -1)
-                    {
-                        nSoftBreak = nPos;
-                    }
-                    SAL_WARN_IF( nSoftBreak >= nBreakPos, "vcl", "Break?!" );
-                    css::i18n::LineBreakHyphenationOptions aHyphOptions( 
xHyph, css::uno::Sequence <css::beans::PropertyValue>(), 1 );
-                    css::i18n::LineBreakUserOptions aUserOptions;
-                    css::i18n::LineBreakResults aLBR = xBI->getLineBreak( 
rStr, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
-                    nBreakPos = aLBR.breakIndex;
-                    if ( nBreakPos <= nPos )
-                        nBreakPos = nSoftBreak;
-                    if ( bHyphenate )
-                    {
-                        // Whether hyphen or not: Put the word after the 
hyphen through
-                        // word boundary.
+    tools::Long nMaxLineWidth  = 0;
+    const bool bHyphenate = (nStyle & DrawTextFlags::WordBreakHyphenation) == 
DrawTextFlags::WordBreakHyphenation;
+    css::uno::Reference< css::linguistic2::XHyphenator > xHyph;
+    if (bHyphenate)
+    {
+        // get service provider
+        css::uno::Reference<css::uno::XComponentContext> 
xContext(comphelper::getProcessComponentContext());
+        css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLinguMgr 
= css::linguistic2::LinguServiceManager::create(xContext);
+        xHyph = xLinguMgr->getHyphenator();
+    }
 
-                        // nMaxBreakPos the last char that fits into the line
-                        // nBreakPos is the word's start
+    css::uno::Reference<css::i18n::XBreakIterator> xBI;
+    sal_Int32 nPos = 0;
+    sal_Int32 nLen = rStr.getLength();
+    while ( nPos < nLen )
+    {
+        sal_Int32 nBreakPos = nPos;
 
-                        // We run into a problem if the doc is so narrow, that 
a word
-                        // is broken into more than two lines ...
-                        if ( xHyph.is() )
-                        {
-                            css::i18n::Boundary aBoundary = 
xBI->getWordBoundary( rStr, nBreakPos, rDefLocale, 
css::i18n::WordType::DICTIONARY_WORD, true );
-                            sal_Int32 nWordStart = nPos;
-                            sal_Int32 nWordEnd = aBoundary.endPos;
-                            SAL_WARN_IF( nWordEnd <= nWordStart, "vcl", 
"ImpBreakLine: Start >= End?" );
+        while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( 
rStr[ nBreakPos ] != '\n' ) )
+            nBreakPos++;
 
-                            sal_Int32 nWordLen = nWordEnd - nWordStart;
-                            if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 
) )
-                            {
-                                // #104415# May happen, because getLineBreak 
may differ from getWordBoundary with DICTIONARY_WORD
-                                // SAL_WARN_IF( nWordEnd < nMaxBreakPos, 
"vcl", "Hyph: Break?" );
-                                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())
-                                {
-                                    bool bAlternate = 
xHyphWord->isAlternativeSpelling();
-                                    sal_Int32 _nWordLen = 1 + 
xHyphWord->getHyphenPos();
-
-                                    if ( ( _nWordLen >= 2 ) && ( 
(nWordStart+_nWordLen) >= 2 ) )
-                                    {
-                                        if ( !bAlternate )
-                                        {
-                                            nBreakPos = nWordStart + _nWordLen;
-                                        }
-                                        else
-                                        {
-                                            OUString aAlt( 
xHyphWord->getHyphenatedWord() );
-
-                                            // We can have two cases:
-                                            // 1) "packen" turns into "pak-ken"
-                                            // 2) "Schiffahrt" turns into 
"Schiff-fahrt"
-
-                                            // In case 1 we need to replace a 
char
-                                            // In case 2 we add a char
-
-                                            // Correct recognition is made 
harder by words such as
-                                            // "Schiffahrtsbrennesseln", as 
the Hyphenator splits all
-                                            // positions of the word and comes 
up with "Schifffahrtsbrennnesseln"
-                                            // Thus, we cannot infer the aWord 
from the AlternativeWord's
-                                            // index.
-                                            // TODO: The whole junk will be 
made easier by a function in
-                                            // the Hyphenator, as soon as AMA 
adds it.
-                                            sal_Int32 nAltStart = _nWordLen - 
1;
-                                            sal_Int32 nTxtStart = nAltStart - 
(aAlt.getLength() - aWord.getLength());
-                                            sal_Int32 nTxtEnd = nTxtStart;
-                                            sal_Int32 nAltEnd = nAltStart;
-
-                                            // The area between nStart and 
nEnd is the difference
-                                            // between AlternativeString and 
OriginalString
-                                            while( nTxtEnd < aWord.getLength() 
&& nAltEnd < aAlt.getLength() &&
-                                                   aWord[nTxtEnd] != 
aAlt[nAltEnd] )
-                                            {
-                                                ++nTxtEnd;
-                                                ++nAltEnd;
-                                            }
-
-                                            // If a char was added, we notice 
it now:
-                                            if( nAltEnd > nTxtEnd && nAltStart 
== nAltEnd &&
-                                                aWord[ nTxtEnd ] == 
aAlt[nAltEnd] )
-                                            {
-                                                ++nAltEnd;
-                                                ++nTxtStart;
-                                                ++nTxtEnd;
-                                            }
-
-                                            SAL_WARN_IF( ( nAltEnd - nAltStart 
) != 1, "vcl", "Alternate: Wrong assumption!" );
-
-                                            sal_Unicode cAlternateReplChar = 0;
-                                            if ( nTxtEnd > nTxtStart )
-                                                cAlternateReplChar = aAlt[ 
nAltStart ];
-
-                                            nBreakPos = nWordStart + nTxtStart;
-                                            if ( cAlternateReplChar )
-                                                nBreakPos++;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    nLineWidth = _rLayout.GetTextWidth( rStr, nPos, 
nBreakPos-nPos );
-                }
-                else
-                {
-                    // fallback to something really simple
-                    sal_Int32 nSpacePos = rStr.getLength();
-                    tools::Long nW = 0;
-                    do
-                    {
-                        nSpacePos = rStr.lastIndexOf( ' ', nSpacePos );
-                        if( nSpacePos != -1 )
-                        {
-                            if( nSpacePos > nPos )
-                                nSpacePos--;
-                            nW = _rLayout.GetTextWidth( rStr, nPos, 
nSpacePos-nPos );
-                        }
-                    } while( nW > nWidth );
+        tools::Long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, 
nBreakPos-nPos );
+        if ( ( nLineWidth > nWidth ) && ( nStyle & DrawTextFlags::WordBreak ) )
+        {
+            if ( !xBI.is() )
+                xBI = vcl::unohelper::CreateBreakIterator();
 
-                    if( nSpacePos != -1 )
-                    {
-                        nBreakPos = nSpacePos;
-                        nLineWidth = _rLayout.GetTextWidth( rStr, nPos, 
nBreakPos-nPos );
-                        if( nBreakPos < rStr.getLength()-1 )
-                            nBreakPos++;
-                    }
-                }
-            }
+            if ( xBI.is() )
+                nBreakPos = ImplBreakLinesWithIterator(nWidth, rStr, _rLayout, 
xHyph, xBI, bHyphenate, nPos, nBreakPos);
+            else
+                // fallback to something really simple
+                nBreakPos = ImplBreakLinesSimple(nWidth, rStr, _rLayout, nPos, 
nBreakPos, nLineWidth);
+        }
 
-            if ( nLineWidth > nMaxLineWidth )
-                nMaxLineWidth = nLineWidth;
+        if ( nLineWidth > nMaxLineWidth )
+            nMaxLineWidth = nLineWidth;
 
-            rLineInfo.AddLine( ImplTextLineInfo( nLineWidth, nPos, 
nBreakPos-nPos ) );
+        rLineInfo.AddLine( ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos 
) );
 
-            if ( nBreakPos == nPos )
-                nBreakPos++;
-            nPos = nBreakPos;
+        if ( nBreakPos == nPos )
+            nBreakPos++;
+        nPos = nBreakPos;
 
-            if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] 
== '\n' ) ) )
-            {
+        if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] == 
'\n' ) ) )
+        {
+            nPos++;
+            // CR/LF?
+            if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ nPos-1 
] == '\r' ) )
                 nPos++;
-                // CR/LF?
-                if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ 
nPos-1 ] == '\r' ) )
-                    nPos++;
-            }
         }
     }
+
 #ifdef DBG_UTIL
     for ( sal_Int32 nL = 0; nL < rLineInfo.Count(); nL++ )
     {
@@ -685,6 +556,149 @@ tools::Long OutputDevice::ImplGetTextLines( 
ImplMultiTextLineInfo& rLineInfo,
     return nMaxLineWidth;
 }
 
+sal_Int32 OutputDevice::ImplBreakLinesWithIterator(const tools::Long nWidth, 
const OUString& rStr, const vcl::ITextLayout& _rLayout,
+                    const css::uno::Reference< css::linguistic2::XHyphenator 
>& xHyph,
+                    const css::uno::Reference<css::i18n::XBreakIterator>& xBI,
+                    const bool bHyphenate,
+                    const sal_Int32 nPos, sal_Int32 nBreakPos)
+{
+    const css::lang::Locale& 
rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
+    sal_Int32 nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, 
nBreakPos - nPos );
+    if (nSoftBreak == -1)
+    {
+        nSoftBreak = nPos;
+    }
+    SAL_WARN_IF( nSoftBreak >= nBreakPos, "vcl", "Break?!" );
+    css::i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, 
css::uno::Sequence <css::beans::PropertyValue>(), 1 );
+    css::i18n::LineBreakUserOptions aUserOptions;
+    css::i18n::LineBreakResults aLBR = xBI->getLineBreak( rStr, nSoftBreak, 
rDefLocale, nPos, aHyphOptions, aUserOptions );
+    nBreakPos = aLBR.breakIndex;
+    if ( nBreakPos <= nPos )
+        nBreakPos = nSoftBreak;
+    if ( !bHyphenate )
+        return nBreakPos;
+
+    // Whether hyphen or not: Put the word after the hyphen through
+    // word boundary.
+
+    // nMaxBreakPos the last char that fits into the line
+    // nBreakPos is the word's start
+
+    // 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;
+    sal_Int32 nWordEnd = aBoundary.endPos;
+    SAL_WARN_IF( nWordEnd <= nWordStart, "vcl", "ImpBreakLine: Start >= End?" 
);
+
+    sal_Int32 nWordLen = nWordEnd - nWordStart;
+    if ( ( nWordEnd < nSoftBreak ) || ( nWordLen <= 3 ) )
+        return nBreakPos;
+
+    // #104415# May happen, because getLineBreak may differ from 
getWordBoundary with DICTIONARY_WORD
+    // SAL_WARN_IF( nWordEnd < nMaxBreakPos, "vcl", "Hyph: Break?" );
+    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;
+
+    bool bAlternate = xHyphWord->isAlternativeSpelling();
+    sal_Int32 _nWordLen = 1 + xHyphWord->getHyphenPos();
+
+    if ( ( _nWordLen < 2 ) || ( (nWordStart+_nWordLen) < 2 ) )
+        return nBreakPos;
+
+    if ( bAlternate )
+    {
+        nBreakPos = nWordStart + _nWordLen;
+        return nBreakPos;
+    }
+
+
+    OUString aAlt( xHyphWord->getHyphenatedWord() );
+
+    // We can have two cases:
+    // 1) "packen" turns into "pak-ken"
+    // 2) "Schiffahrt" turns into "Schiff-fahrt"
+
+    // In case 1 we need to replace a char
+    // In case 2 we add a char
+
+    // Correct recognition is made harder by words such as
+    // "Schiffahrtsbrennesseln", as the Hyphenator splits all
+    // positions of the word and comes up with "Schifffahrtsbrennnesseln"
+    // Thus, we cannot infer the aWord from the AlternativeWord's
+    // index.
+    // TODO: The whole junk will be made easier by a function in
+    // the Hyphenator, as soon as AMA adds it.
+    sal_Int32 nAltStart = _nWordLen - 1;
+    sal_Int32 nTxtStart = nAltStart - (aAlt.getLength() - aWord.getLength());
+    sal_Int32 nTxtEnd = nTxtStart;
+    sal_Int32 nAltEnd = nAltStart;
+
+    // The area between nStart and nEnd is the difference
+    // between AlternativeString and OriginalString
+    while( nTxtEnd < aWord.getLength() && nAltEnd < aAlt.getLength() &&
+           aWord[nTxtEnd] != aAlt[nAltEnd] )
+    {
+        ++nTxtEnd;
+        ++nAltEnd;
+    }
+
+    // If a char was added, we notice it now:
+    if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
+        aWord[ nTxtEnd ] == aAlt[nAltEnd] )
+    {
+        ++nAltEnd;
+        ++nTxtStart;
+        ++nTxtEnd;
+    }
+
+    SAL_WARN_IF( ( nAltEnd - nAltStart ) != 1, "vcl", "Alternate: Wrong 
assumption!" );
+
+    sal_Unicode cAlternateReplChar = 0;
+    if ( nTxtEnd > nTxtStart )
+        cAlternateReplChar = aAlt[ nAltStart ];
+
+    nBreakPos = nWordStart + nTxtStart;
+    if ( cAlternateReplChar )
+        nBreakPos++;
+    return nBreakPos;
+}
+
+sal_Int32 OutputDevice::ImplBreakLinesSimple( const tools::Long nWidth, const 
OUString& rStr,
+                        const vcl::ITextLayout& _rLayout, const sal_Int32 
nPos, sal_Int32 nBreakPos, tools::Long& nLineWidth )
+{
+    sal_Int32 nSpacePos = rStr.getLength();
+    tools::Long nW = 0;
+    do
+    {
+        nSpacePos = rStr.lastIndexOf( ' ', nSpacePos );
+        if( nSpacePos != -1 )
+        {
+            if( nSpacePos > nPos )
+                nSpacePos--;
+            nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
+        }
+    } while( nW > nWidth );
+
+    if( nSpacePos != -1 )
+    {
+        nBreakPos = nSpacePos;
+        nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
+        if( nBreakPos < rStr.getLength()-1 )
+            nBreakPos++;
+    }
+    return nBreakPos;
+}
+
+
 void OutputDevice::SetTextColor( const Color& rColor )
 {
 

Reply via email to