summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2021-10-26 09:15:17 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2021-10-26 10:31:44 +0200
commit4fc1b3fb659be916167518b49ffe8193e9033f30 (patch)
treeb3e8dae82f9546d46352c903987b0b8710d5c7a4 /vcl
parent9142f66ec1c78292dd2b8863c622dfb705dd2db2 (diff)
flatten ImplGetTextLines
Change-Id: Iefbbcb186b2811748abf49546351a2c68e8af462 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124155 Tested-by: Noel Grandin <noel.grandin@collabora.co.uk> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/outdev/text.cxx358
1 files changed, 186 insertions, 172 deletions
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 )
{