include/vcl/outdev.hxx            |   23 --
 include/vcl/window.hxx            |    2 
 vcl/inc/textlayout.hxx            |   26 ++
 vcl/source/gdi/pdfwriter_impl.cxx |    2 
 vcl/source/gdi/textlayout.cxx     |  396 ++++++++++++++++++++++++++++++++++-
 vcl/source/outdev/text.cxx        |  427 +-------------------------------------
 vcl/source/window/window3.cxx     |    2 
 7 files changed, 442 insertions(+), 436 deletions(-)

New commits:
commit 41e00b105f004b75451e24043dc85af703c91dd3
Author:     Chris Sherlock <chris.sherloc...@gmail.com>
AuthorDate: Mon Sep 25 00:24:32 2023 +1000
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Mon Oct 23 09:42:11 2023 +0200

    vcl: migrate text layout functions out of OutputDevice
    
    OutputDevice is not where text layout should be done. There are a number
    of text layout functions that are used across the text layout classes,
    so I have moved them into TextLayoutHelper and made the text layout
    classes rely on this. I have made TextLayoutHelper implement the
    ITextLayout interface because this is still useful to new classes that
    need to implement new text layout functionality.
    
    Change-Id: Ic137a938576e7a6a64db0e5780bbbdd8342ef421
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157362
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 4a6d217c2cb6..bea1e00d9b7f 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -102,7 +102,7 @@ class SalLayoutGlyphs;
 namespace vcl
 {
     class ExtOutDevData;
-    class ITextLayout;
+    class TextLayoutCommon;
     struct FontCapabilities;
     class Window;
     class WindowOutputDevice;
@@ -869,11 +869,11 @@ public:
     void                        DrawText( const tools::Rectangle& rRect,
                                           const OUString& rStr, DrawTextFlags 
nStyle = DrawTextFlags::NONE,
                                           std::vector< tools::Rectangle >* 
pVector = nullptr, OUString* pDisplayText = nullptr,
-                                          vcl::ITextLayout* _pTextLayout = 
nullptr );
+                                          vcl::TextLayoutCommon* _pTextLayout 
= nullptr );
 
     static void                 ImplDrawText( OutputDevice& rTargetDevice, 
const tools::Rectangle& rRect,
                                               const OUString& rOrigStr, 
DrawTextFlags nStyle,
-                                              std::vector< tools::Rectangle >* 
pVector, OUString* pDisplayText, vcl::ITextLayout& _rLayout );
+                                              std::vector< tools::Rectangle >* 
pVector, OUString* pDisplayText, vcl::TextLayoutCommon& _rLayout );
 
     void                        ImplDrawText( SalLayout& );
 
@@ -904,7 +904,7 @@ public:
     tools::Rectangle                   GetTextRect( const tools::Rectangle& 
rRect,
                                              const OUString& rStr, 
DrawTextFlags nStyle = DrawTextFlags::WordBreak,
                                              TextRectInfo* pInfo = nullptr,
-                                             const vcl::ITextLayout* 
_pTextLayout = nullptr ) const;
+                                             const vcl::TextLayoutCommon* 
_pTextLayout = nullptr ) const;
 
     /** Return the exact bounding rectangle of rStr.
 
@@ -1073,17 +1073,6 @@ public:
 protected:
     SAL_DLLPRIVATE void         ImplInitTextLineSize();
     SAL_DLLPRIVATE void         ImplInitAboveTextLineSize();
-    static
-    SAL_DLLPRIVATE tools::Long  ImplGetTextLines( const tools::Rectangle& 
rRect, tools::Long nTextHeight, 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;
@@ -1200,10 +1189,6 @@ private:
 
     SAL_DLLPRIVATE static void  ImplUpdateFontDataForAllFrames( 
FontUpdateHandler_t pHdl, bool bNewFontLists );
 
-    static
-    SAL_DLLPRIVATE OUString     ImplGetEllipsisString( const OUString& rStr,
-                                                       tools::Long nMaxWidth, 
DrawTextFlags nStyle, const vcl::ITextLayout& _rLayout );
-
     SAL_DLLPRIVATE void         ImplDrawEmphasisMark( tools::Long nBaseX, 
tools::Long nX, tools::Long nY, const tools::PolyPolygon& rPolyPoly, bool 
bPolyLine, const tools::Rectangle& rRect1, const tools::Rectangle& rRect2 );
     SAL_DLLPRIVATE void         ImplDrawEmphasisMarks( SalLayout& );
     ///@}
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 73f2e4e5bc03..640e9c6c9983 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -1494,7 +1494,7 @@ public:
     tools::Rectangle            GetTextRect( const tools::Rectangle& rRect,
                                              const OUString& rStr, 
DrawTextFlags nStyle = DrawTextFlags::WordBreak,
                                              TextRectInfo* pInfo = nullptr,
-                                             const vcl::ITextLayout* 
_pTextLayout = nullptr ) const;
+                                             const vcl::TextLayoutCommon* 
_pTextLayout = nullptr ) const;
     float                       GetDPIScaleFactor() const;
     tools::Long                 GetOutOffXPixel() const;
     tools::Long                 GetOutOffYPixel() const;
diff --git a/vcl/inc/textlayout.hxx b/vcl/inc/textlayout.hxx
index 5938a9d58ef7..ee9eb9e39266 100644
--- a/vcl/inc/textlayout.hxx
+++ b/vcl/inc/textlayout.hxx
@@ -26,6 +26,10 @@
 #include <memory>
 #include <vector>
 
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
+
 class Control;
 
 namespace vcl
@@ -44,10 +48,30 @@ namespace vcl
         ~ITextLayout() COVERITY_NOEXCEPT_FALSE {}
     };
 
+    class TextLayoutCommon : public ITextLayout
+    {
+    public:
+        OUString GetEllipsisString(OUString const& rOrigStr, tools::Long 
nMaxWidth, DrawTextFlags nStyle);
+
+        sal_Int32 BreakLinesWithIterator(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,
+                        const sal_Int32 nPos, sal_Int32 nBreakPos);
+
+        sal_Int32 BreakLinesSimple(const tools::Long nWidth, OUString const& 
rStr,
+                                  const sal_Int32 nPos, sal_Int32 nBreakPos, 
tools::Long& nLineWidth);
+
+        tools::Long GetTextLines(tools::Rectangle const& rRect, const 
tools::Long nTextHeight,
+                                 ImplMultiTextLineInfo& rLineInfo,
+                                 tools::Long nWidth, OUString const& rStr,
+                                 DrawTextFlags nStyle);
+    };
+
     /** is an implementation of the ITextLayout interface which simply 
delegates its calls to the respective
         methods of an OutputDevice instance, without any inbetween magic.
     */
-    class DefaultTextLayout final : public ITextLayout
+    class DefaultTextLayout final : public TextLayoutCommon
     {
     public:
         DefaultTextLayout( OutputDevice& _rTargetDevice )
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index 506fde66b6c7..5699b2dc6ddc 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -7304,7 +7304,7 @@ void PDFWriterImpl::drawText( const tools::Rectangle& 
rRect, const OUString& rOr
         {
             vcl::DefaultTextLayout aLayout( *this );
             OUString               aLastLine;
-            OutputDevice::ImplGetTextLines( rRect, nTextHeight, 
aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
+            aLayout.GetTextLines( rRect, nTextHeight, aMultiLineInfo, nWidth, 
aStr, nStyle );
             sal_Int32              nLines = nHeight/nTextHeight;
             nFormatLines = aMultiLineInfo.Count();
             if ( !nLines )
diff --git a/vcl/source/gdi/textlayout.cxx b/vcl/source/gdi/textlayout.cxx
index dd559ac470dc..2eaf5746f30b 100644
--- a/vcl/source/gdi/textlayout.cxx
+++ b/vcl/source/gdi/textlayout.cxx
@@ -20,23 +20,409 @@
 #include <vcl/ctrl.hxx>
 #include <vcl/kernarray.hxx>
 #include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/unohelp.hxx>
 
 #include <textlayout.hxx>
+#include <textlineinfo.hxx>
 
 #include <osl/diagnose.h>
+#include <osl/file.h>
+#include <rtl/ustrbuf.hxx>
 #include <tools/fract.hxx>
 #include <sal/log.hxx>
-
-#if OSL_DEBUG_LEVEL > 1
-#include <rtl/strbuf.hxx>
-#endif
+#include <comphelper/processfactory.hxx>
+#include <i18nlangtag/languagetag.hxx>
 
 #include <memory>
 #include <iterator>
 
+static bool ImplIsCharIn(sal_Unicode c, const char* pStr)
+{
+    while ( *pStr )
+    {
+        if ( *pStr == c )
+            return true;
+        pStr++;
+    }
+
+    return false;
+}
+
+ImplMultiTextLineInfo::ImplMultiTextLineInfo()
+{
+}
+
+ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
+{
+}
+
+void ImplMultiTextLineInfo::AddLine( const ImplTextLineInfo& rLine )
+{
+    mvLines.push_back(rLine);
+}
+
+void ImplMultiTextLineInfo::Clear()
+{
+    mvLines.clear();
+}
+
 namespace vcl
 {
 
+    OUString TextLayoutCommon::GetEllipsisString(OUString const& rOrigStr, 
tools::Long nMaxWidth, DrawTextFlags nStyle)
+    {
+        OUString aStr = rOrigStr;
+        sal_Int32 nIndex = GetTextBreak( aStr, nMaxWidth, 0, aStr.getLength() 
);
+
+        if ( nIndex != -1 )
+        {
+            if( (nStyle & DrawTextFlags::CenterEllipsis) == 
DrawTextFlags::CenterEllipsis )
+            {
+                OUStringBuffer aTmpStr( aStr );
+                // speed it up by removing all but 1.33x as many as the break 
pos.
+                sal_Int32 nEraseChars = std::max<sal_Int32>(4, 
aStr.getLength() - (nIndex*4)/3);
+                while( nEraseChars < aStr.getLength() && GetTextWidth( 
aTmpStr.toString(), 0, aTmpStr.getLength() ) > nMaxWidth )
+                {
+                    aTmpStr = aStr;
+                    sal_Int32 i = (aTmpStr.getLength() - nEraseChars)/2;
+                    aTmpStr.remove(i, nEraseChars++);
+                    aTmpStr.insert(i, "...");
+                }
+                aStr = aTmpStr.makeStringAndClear();
+            }
+            else if ( nStyle & DrawTextFlags::EndEllipsis )
+            {
+                aStr = aStr.copy(0, nIndex);
+                if ( nIndex > 1 )
+                {
+                    aStr += "...";
+                    while ( !aStr.isEmpty() && ( GetTextWidth( aStr, 0, 
aStr.getLength() ) > nMaxWidth) )
+                    {
+                        if ( (nIndex > 1) || (nIndex == aStr.getLength()) )
+                            nIndex--;
+                        aStr = aStr.replaceAt( nIndex, 1, u"");
+                    }
+                }
+
+                if ( aStr.isEmpty() && (nStyle & DrawTextFlags::Clip) )
+                    aStr += OUStringChar(rOrigStr[ 0 ]);
+            }
+            else if ( nStyle & DrawTextFlags::PathEllipsis )
+            {
+                OUString aPath( rOrigStr );
+                OUString aAbbreviatedPath;
+                osl_abbreviateSystemPath( aPath.pData, 
&aAbbreviatedPath.pData, nIndex, nullptr );
+                aStr = aAbbreviatedPath;
+            }
+            else if ( nStyle & DrawTextFlags::NewsEllipsis )
+            {
+                static char const   pSepChars[] = ".";
+                // Determine last section
+                sal_Int32 nLastContent = aStr.getLength();
+                while ( nLastContent )
+                {
+                    nLastContent--;
+                    if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
+                        break;
+                }
+                while ( nLastContent &&
+                        ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
+                    nLastContent--;
+
+                OUString aLastStr = aStr.copy(nLastContent);
+                OUString aTempLastStr1 = "..." + aLastStr;
+                if ( GetTextWidth( aTempLastStr1, 0, aTempLastStr1.getLength() 
) > nMaxWidth )
+                    aStr = GetEllipsisString( aStr, nMaxWidth, nStyle | 
DrawTextFlags::EndEllipsis );
+                else
+                {
+                    sal_Int32 nFirstContent = 0;
+                    while ( nFirstContent < nLastContent )
+                    {
+                        nFirstContent++;
+                        if ( ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
+                            break;
+                    }
+                    while ( (nFirstContent < nLastContent) &&
+                            ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
+                        nFirstContent++;
+                    // MEM continue here
+                    if ( nFirstContent >= nLastContent )
+                        aStr = GetEllipsisString( aStr, nMaxWidth, nStyle | 
DrawTextFlags::EndEllipsis );
+                    else
+                    {
+                        if ( nFirstContent > 4 )
+                            nFirstContent = 4;
+                        OUString aFirstStr = OUString::Concat(aStr.subView( 0, 
nFirstContent )) + "...";
+                        OUString aTempStr = aFirstStr + aLastStr;
+                        if ( GetTextWidth( aTempStr, 0, aTempStr.getLength() ) 
> nMaxWidth )
+                            aStr = GetEllipsisString( aStr, nMaxWidth, nStyle 
| DrawTextFlags::EndEllipsis );
+                        else
+                        {
+                            do
+                            {
+                                aStr = aTempStr;
+                                if( nLastContent > aStr.getLength() )
+                                    nLastContent = aStr.getLength();
+                                while ( nFirstContent < nLastContent )
+                                {
+                                    nLastContent--;
+                                    if ( ImplIsCharIn( aStr[ nLastContent ], 
pSepChars ) )
+                                        break;
+
+                                }
+                                while ( (nFirstContent < nLastContent) &&
+                                        ImplIsCharIn( aStr[ nLastContent-1 ], 
pSepChars ) )
+                                    nLastContent--;
+
+                                if ( nFirstContent < nLastContent )
+                                {
+                                    std::u16string_view aTempLastStr = 
aStr.subView( nLastContent );
+                                    aTempStr = aFirstStr + aTempLastStr;
+
+                                    if ( GetTextWidth( aTempStr, 0, 
aTempStr.getLength() ) > nMaxWidth )
+                                        break;
+                                }
+                            }
+                            while ( nFirstContent < nLastContent );
+                        }
+                    }
+                }
+            }
+        }
+
+        return aStr;
+    }
+
+    sal_Int32 TextLayoutCommon::BreakLinesWithIterator(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,
+                        const sal_Int32 nPos, sal_Int32 nBreakPos)
+    {
+        const css::lang::Locale& 
rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
+        sal_Int32 nSoftBreak = 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_INFO_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 TextLayoutCommon::BreakLinesSimple(const tools::Long nWidth, 
OUString const& rStr,
+                                                 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 = GetTextWidth( rStr, nPos, nSpacePos-nPos );
+            }
+        } while( nW > nWidth );
+
+        if( nSpacePos != -1 )
+        {
+            nBreakPos = nSpacePos;
+            nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos );
+            if( nBreakPos < rStr.getLength()-1 )
+                nBreakPos++;
+        }
+        return nBreakPos;
+    }
+
+    tools::Long TextLayoutCommon::GetTextLines(tools::Rectangle const& rRect, 
const tools::Long nTextHeight,
+                                               ImplMultiTextLineInfo& 
rLineInfo,
+                                               tools::Long nWidth, OUString 
const& rStr,
+                                               DrawTextFlags nStyle)
+    {
+        SAL_WARN_IF( nWidth <= 0, "vcl", "ImplGetTextLines: nWidth <= 0!" );
+
+        if ( nWidth <= 0 )
+            nWidth = 1;
+
+        rLineInfo.Clear();
+        if (rStr.isEmpty())
+            return 0;
+
+        const bool bClipping = (nStyle & DrawTextFlags::Clip) && !(nStyle & 
DrawTextFlags::EndEllipsis);
+
+        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();
+        }
+
+        css::uno::Reference<css::i18n::XBreakIterator> xBI;
+        sal_Int32 nPos = 0;
+        sal_Int32 nLen = rStr.getLength();
+        sal_Int32 nCurrentTextY = 0;
+        while ( nPos < nLen )
+        {
+            sal_Int32 nBreakPos = nPos;
+
+            while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( 
rStr[ nBreakPos ] != '\n' ) )
+                nBreakPos++;
+
+            tools::Long nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos 
);
+            if ( ( nLineWidth > nWidth ) && ( nStyle & 
DrawTextFlags::WordBreak ) )
+            {
+                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);
+            }
+
+            if ( nLineWidth > nMaxLineWidth )
+                nMaxLineWidth = nLineWidth;
+
+            rLineInfo.AddLine( ImplTextLineInfo( nLineWidth, nPos, 
nBreakPos-nPos ) );
+
+            if ( nBreakPos == nPos )
+                nBreakPos++;
+            nPos = nBreakPos;
+
+            if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] 
== '\n' ) ) )
+            {
+                nPos++;
+                // CR/LF?
+                if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ 
nPos-1 ] == '\r' ) )
+                    nPos++;
+            }
+            nCurrentTextY += nTextHeight;
+            if (bClipping && nCurrentTextY > rRect.GetHeight())
+                break;
+        }
+
+#ifdef DBG_UTIL
+        for ( sal_Int32 nL = 0; nL < rLineInfo.Count(); nL++ )
+        {
+            ImplTextLineInfo& rLine = rLineInfo.GetLine( nL );
+            OUString aLine = rStr.copy( rLine.GetIndex(), rLine.GetLen() );
+            SAL_WARN_IF( aLine.indexOf( '\r' ) != -1, "vcl", "ImplGetTextLines 
- Found CR!" );
+            SAL_WARN_IF( aLine.indexOf( '\n' ) != -1, "vcl", "ImplGetTextLines 
- Found LF!" );
+        }
+#endif
+
+        return nMaxLineWidth;
+    }
+
     DefaultTextLayout::~DefaultTextLayout()
     {
     }
@@ -68,7 +454,7 @@ namespace vcl
         return false;
     }
 
-    class ReferenceDeviceTextLayout : public ITextLayout
+    class ReferenceDeviceTextLayout : public TextLayoutCommon
     {
     public:
         ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& 
_rTargetDevice, OutputDevice& _rReferenceDevice );
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index c2978d971659..1b40a1b2de28 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -19,11 +19,8 @@
 
 #include <sal/config.h>
 
-#include <osl/file.h>
-#include <rtl/ustrbuf.hxx>
 #include <sal/log.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
-#include <comphelper/processfactory.hxx>
 #include <tools/lineend.hxx>
 #include <tools/debug.hxx>
 #include <unotools/configmgr.hxx>
@@ -35,7 +32,6 @@
 #include <vcl/textrectinfo.hxx>
 #include <vcl/virdev.hxx>
 #include <vcl/sysdata.hxx>
-#include <vcl/unohelp.hxx>
 
 #include <ImplLayoutArgs.hxx>
 #include <ImplOutDevData.hxx>
@@ -48,10 +44,6 @@
 #include <TextLayoutCache.hxx>
 #include <font/PhysicalFontFace.hxx>
 
-#include <com/sun/star/i18n/WordType.hpp>
-#include <com/sun/star/i18n/XBreakIterator.hpp>
-#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
-
 #include <memory>
 #include <optional>
 
@@ -79,24 +71,6 @@ void OutputDevice::SetDigitLanguage( LanguageType 
eTextLanguage )
         mpAlphaVDev->SetDigitLanguage( eTextLanguage );
 }
 
-ImplMultiTextLineInfo::ImplMultiTextLineInfo()
-{
-}
-
-ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
-{
-}
-
-void ImplMultiTextLineInfo::AddLine( const ImplTextLineInfo& rLine )
-{
-    mvLines.push_back(rLine);
-}
-
-void ImplMultiTextLineInfo::Clear()
-{
-    mvLines.clear();
-}
-
 void OutputDevice::ImplInitTextColor()
 {
     DBG_TESTSOLARMUTEX();
@@ -108,6 +82,13 @@ void OutputDevice::ImplInitTextColor()
     }
 }
 
+OUString OutputDevice::GetEllipsisString( const OUString& rOrigStr, 
tools::Long nMaxWidth,
+                                        DrawTextFlags nStyle ) const
+{
+    vcl::DefaultTextLayout aTextLayout(*const_cast< OutputDevice* >(this));
+    return aTextLayout.GetEllipsisString(rOrigStr, nMaxWidth, nStyle);
+}
+
 void OutputDevice::ImplDrawTextRect( tools::Long nBaseX, tools::Long nBaseY,
                                      tools::Long nDistX, tools::Long nDistY, 
tools::Long nWidth, tools::Long nHeight )
 {
@@ -482,237 +463,6 @@ void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
         ImplDrawTextDirect( rSalLayout, mbTextLines );
 }
 
-tools::Long OutputDevice::ImplGetTextLines( const tools::Rectangle& rRect, 
const tools::Long nTextHeight,
-                                     ImplMultiTextLineInfo& rLineInfo,
-                                     tools::Long nWidth, const OUString& rStr,
-                                     DrawTextFlags nStyle, const 
vcl::ITextLayout& _rLayout )
-{
-    SAL_WARN_IF( nWidth <= 0, "vcl", "ImplGetTextLines: nWidth <= 0!" );
-
-    if ( nWidth <= 0 )
-        nWidth = 1;
-
-    rLineInfo.Clear();
-    if (rStr.isEmpty())
-        return 0;
-
-    const bool bClipping = (nStyle & DrawTextFlags::Clip) && !(nStyle & 
DrawTextFlags::EndEllipsis);
-
-    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();
-    }
-
-    css::uno::Reference<css::i18n::XBreakIterator> xBI;
-    sal_Int32 nPos = 0;
-    sal_Int32 nLen = rStr.getLength();
-    sal_Int32 nCurrentTextY = 0;
-    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 ( xBI.is() )
-            {
-                nBreakPos = ImplBreakLinesWithIterator(nWidth, rStr, _rLayout, 
xHyph, xBI, bHyphenate, nPos, nBreakPos);
-                nLineWidth = _rLayout.GetTextWidth(rStr, nPos, nBreakPos - 
nPos);
-            }
-            else
-                // fallback to something really simple
-                nBreakPos = ImplBreakLinesSimple(nWidth, rStr, _rLayout, nPos, 
nBreakPos, nLineWidth);
-        }
-
-        if ( nLineWidth > nMaxLineWidth )
-            nMaxLineWidth = nLineWidth;
-
-        rLineInfo.AddLine( ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos 
) );
-
-        if ( nBreakPos == nPos )
-            nBreakPos++;
-        nPos = nBreakPos;
-
-        if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] == 
'\n' ) ) )
-        {
-            nPos++;
-            // CR/LF?
-            if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ nPos-1 
] == '\r' ) )
-                nPos++;
-        }
-        nCurrentTextY += nTextHeight;
-        if (bClipping && nCurrentTextY > rRect.GetHeight())
-            break;
-    }
-
-#ifdef DBG_UTIL
-    for ( sal_Int32 nL = 0; nL < rLineInfo.Count(); nL++ )
-    {
-        ImplTextLineInfo& rLine = rLineInfo.GetLine( nL );
-        OUString aLine = rStr.copy( rLine.GetIndex(), rLine.GetLen() );
-        SAL_WARN_IF( aLine.indexOf( '\r' ) != -1, "vcl", "ImplGetTextLines - 
Found CR!" );
-        SAL_WARN_IF( aLine.indexOf( '\n' ) != -1, "vcl", "ImplGetTextLines - 
Found LF!" );
-    }
-#endif
-
-    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_INFO_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 )
 {
 
@@ -1538,7 +1288,7 @@ sal_Int32 OutputDevice::GetTextBreak( const OUString& 
rStr, tools::Long nTextWid
 void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const 
tools::Rectangle& rRect,
                                  const OUString& rOrigStr, DrawTextFlags 
nStyle,
                                  std::vector< tools::Rectangle >* pVector, 
OUString* pDisplayText,
-                                 vcl::ITextLayout& _rLayout )
+                                 vcl::TextLayoutCommon& _rLayout )
 {
 
     Color aOldTextColor;
@@ -1617,7 +1367,7 @@ void OutputDevice::ImplDrawText( OutputDevice& 
rTargetDevice, const tools::Recta
 
         if ( nTextHeight )
         {
-            tools::Long nMaxTextWidth = ImplGetTextLines( rRect, nTextHeight, 
aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
+            tools::Long nMaxTextWidth = _rLayout.GetTextLines(rRect, 
nTextHeight, aMultiLineInfo, nWidth, aStr, nStyle);
             sal_Int32 nLines = static_cast<sal_Int32>(nHeight/nTextHeight);
             OUString aLastLine;
             nFormatLines = aMultiLineInfo.Count();
@@ -1641,7 +1391,7 @@ void OutputDevice::ImplDrawText( OutputDevice& 
rTargetDevice, const tools::Recta
                             aLastLineBuffer[ i ] = ' ';
                     }
                     aLastLine = aLastLineBuffer.makeStringAndClear();
-                    aLastLine = ImplGetEllipsisString( aLastLine, nWidth, 
nStyle, _rLayout );
+                    aLastLine = _rLayout.GetEllipsisString(aLastLine, nWidth, 
nStyle);
                     nStyle &= ~DrawTextFlags(DrawTextFlags::VCenter | 
DrawTextFlags::Bottom);
                     nStyle |= DrawTextFlags::Top;
                 }
@@ -1728,7 +1478,7 @@ void OutputDevice::ImplDrawText( OutputDevice& 
rTargetDevice, const tools::Recta
         {
             if ( nStyle & TEXT_DRAW_ELLIPSIS )
             {
-                aStr = ImplGetEllipsisString( aStr, nWidth, nStyle, _rLayout );
+                aStr = _rLayout.GetEllipsisString(aStr, nWidth, nStyle);
                 nStyle &= ~DrawTextFlags(DrawTextFlags::Center | 
DrawTextFlags::Right);
                 nStyle |= DrawTextFlags::Left;
                 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.getLength() 
);
@@ -1834,7 +1584,7 @@ void OutputDevice::AddTextRectActions( const 
tools::Rectangle& rRect,
 
 void OutputDevice::DrawText( const tools::Rectangle& rRect, const OUString& 
rOrigStr, DrawTextFlags nStyle,
                              std::vector< tools::Rectangle >* pVector, 
OUString* pDisplayText,
-                             vcl::ITextLayout* _pTextLayout )
+                             vcl::TextLayoutCommon* _pTextLayout )
 {
     assert(!is_double_buffered_window());
 
@@ -1881,7 +1631,7 @@ void OutputDevice::DrawText( const tools::Rectangle& 
rRect, const OUString& rOri
 tools::Rectangle OutputDevice::GetTextRect( const tools::Rectangle& rRect,
                                      const OUString& rStr, DrawTextFlags 
nStyle,
                                      TextRectInfo* pInfo,
-                                     const vcl::ITextLayout* _pTextLayout ) 
const
+                                     const vcl::TextLayoutCommon* _pTextLayout 
) const
 {
 
     tools::Rectangle           aRect = rRect;
@@ -1902,7 +1652,12 @@ tools::Rectangle OutputDevice::GetTextRect( const 
tools::Rectangle& rRect,
 
         nMaxWidth = 0;
         vcl::DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( 
this ) );
-        ImplGetTextLines( rRect, nTextHeight, aMultiLineInfo, nWidth, aStr, 
nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
+
+        if (_pTextLayout)
+            
const_cast<vcl::TextLayoutCommon*>(_pTextLayout)->GetTextLines(rRect, 
nTextHeight, aMultiLineInfo, nWidth, aStr, nStyle);
+        else
+            aDefaultLayout.GetTextLines(rRect, nTextHeight, aMultiLineInfo, 
nWidth, aStr, nStyle);
+
         nFormatLines = aMultiLineInfo.Count();
         if ( !nTextHeight )
             nTextHeight = 1;
@@ -2002,150 +1757,6 @@ tools::Rectangle OutputDevice::GetTextRect( const 
tools::Rectangle& rRect,
     return aRect;
 }
 
-static bool ImplIsCharIn( sal_Unicode c, const char* pStr )
-{
-    while ( *pStr )
-    {
-        if ( *pStr == c )
-            return true;
-        pStr++;
-    }
-
-    return false;
-}
-
-OUString OutputDevice::GetEllipsisString( const OUString& rOrigStr, 
tools::Long nMaxWidth,
-                                        DrawTextFlags nStyle ) const
-{
-    vcl::DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
-    return ImplGetEllipsisString( rOrigStr, nMaxWidth, nStyle, aTextLayout );
-}
-
-OUString OutputDevice::ImplGetEllipsisString( const OUString& rOrigStr, 
tools::Long nMaxWidth,
-                                               DrawTextFlags nStyle, const 
vcl::ITextLayout& _rLayout )
-{
-    OUString aStr = rOrigStr;
-    sal_Int32 nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, 
aStr.getLength() );
-
-    if ( nIndex != -1 )
-    {
-        if( (nStyle & DrawTextFlags::CenterEllipsis) == 
DrawTextFlags::CenterEllipsis )
-        {
-            OUStringBuffer aTmpStr( aStr );
-            // speed it up by removing all but 1.33x as many as the break pos.
-            sal_Int32 nEraseChars = std::max<sal_Int32>(4, aStr.getLength() - 
(nIndex*4)/3);
-            while( nEraseChars < aStr.getLength() && _rLayout.GetTextWidth( 
aTmpStr.toString(), 0, aTmpStr.getLength() ) > nMaxWidth )
-            {
-                aTmpStr = aStr;
-                sal_Int32 i = (aTmpStr.getLength() - nEraseChars)/2;
-                aTmpStr.remove(i, nEraseChars++);
-                aTmpStr.insert(i, "...");
-            }
-            aStr = aTmpStr.makeStringAndClear();
-        }
-        else if ( nStyle & DrawTextFlags::EndEllipsis )
-        {
-            aStr = aStr.copy(0, nIndex);
-            if ( nIndex > 1 )
-            {
-                aStr += "...";
-                while ( !aStr.isEmpty() && (_rLayout.GetTextWidth( aStr, 0, 
aStr.getLength() ) > nMaxWidth) )
-                {
-                    if ( (nIndex > 1) || (nIndex == aStr.getLength()) )
-                        nIndex--;
-                    aStr = aStr.replaceAt( nIndex, 1, u"");
-                }
-            }
-
-            if ( aStr.isEmpty() && (nStyle & DrawTextFlags::Clip) )
-                aStr += OUStringChar(rOrigStr[ 0 ]);
-        }
-        else if ( nStyle & DrawTextFlags::PathEllipsis )
-        {
-            OUString aPath( rOrigStr );
-            OUString aAbbreviatedPath;
-            osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, 
nIndex, nullptr );
-            aStr = aAbbreviatedPath;
-        }
-        else if ( nStyle & DrawTextFlags::NewsEllipsis )
-        {
-            static char const   pSepChars[] = ".";
-            // Determine last section
-            sal_Int32 nLastContent = aStr.getLength();
-            while ( nLastContent )
-            {
-                nLastContent--;
-                if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
-                    break;
-            }
-            while ( nLastContent &&
-                    ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
-                nLastContent--;
-
-            OUString aLastStr = aStr.copy(nLastContent);
-            OUString aTempLastStr1 = "..." + aLastStr;
-            if ( _rLayout.GetTextWidth( aTempLastStr1, 0, 
aTempLastStr1.getLength() ) > nMaxWidth )
-                aStr = OutputDevice::ImplGetEllipsisString( aStr, nMaxWidth, 
nStyle | DrawTextFlags::EndEllipsis, _rLayout );
-            else
-            {
-                sal_Int32 nFirstContent = 0;
-                while ( nFirstContent < nLastContent )
-                {
-                    nFirstContent++;
-                    if ( ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
-                        break;
-                }
-                while ( (nFirstContent < nLastContent) &&
-                        ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
-                    nFirstContent++;
-                // MEM continue here
-                if ( nFirstContent >= nLastContent )
-                    aStr = OutputDevice::ImplGetEllipsisString( aStr, 
nMaxWidth, nStyle | DrawTextFlags::EndEllipsis, _rLayout );
-                else
-                {
-                    if ( nFirstContent > 4 )
-                        nFirstContent = 4;
-                    OUString aFirstStr = OUString::Concat(aStr.subView( 0, 
nFirstContent )) + "...";
-                    OUString aTempStr = aFirstStr + aLastStr;
-                    if ( _rLayout.GetTextWidth( aTempStr, 0, 
aTempStr.getLength() ) > nMaxWidth )
-                        aStr = OutputDevice::ImplGetEllipsisString( aStr, 
nMaxWidth, nStyle | DrawTextFlags::EndEllipsis, _rLayout );
-                    else
-                    {
-                        do
-                        {
-                            aStr = aTempStr;
-                            if( nLastContent > aStr.getLength() )
-                                nLastContent = aStr.getLength();
-                            while ( nFirstContent < nLastContent )
-                            {
-                                nLastContent--;
-                                if ( ImplIsCharIn( aStr[ nLastContent ], 
pSepChars ) )
-                                    break;
-
-                            }
-                            while ( (nFirstContent < nLastContent) &&
-                                    ImplIsCharIn( aStr[ nLastContent-1 ], 
pSepChars ) )
-                                nLastContent--;
-
-                            if ( nFirstContent < nLastContent )
-                            {
-                                std::u16string_view aTempLastStr = 
aStr.subView( nLastContent );
-                                aTempStr = aFirstStr + aTempLastStr;
-
-                                if ( _rLayout.GetTextWidth( aTempStr, 0, 
aTempStr.getLength() ) > nMaxWidth )
-                                    break;
-                            }
-                        }
-                        while ( nFirstContent < nLastContent );
-                    }
-                }
-            }
-        }
-    }
-
-    return aStr;
-}
-
 void OutputDevice::DrawCtrlText( const Point& rPos, const OUString& rStr,
                                  sal_Int32 nIndex, sal_Int32 nLen,
                                  DrawTextFlags nStyle, std::vector< 
tools::Rectangle >* pVector, OUString* pDisplayText,
diff --git a/vcl/source/window/window3.cxx b/vcl/source/window/window3.cxx
index 5b8dd5cff4ec..30c41f5e20f0 100644
--- a/vcl/source/window/window3.cxx
+++ b/vcl/source/window/window3.cxx
@@ -200,7 +200,7 @@ Size Window::LogicToLogic(const Size& rSzSource, const 
MapMode* pMapModeSource,
 
 tools::Rectangle Window::GetTextRect(const tools::Rectangle& rRect, const 
OUString& rStr,
                                      DrawTextFlags nStyle, TextRectInfo* pInfo,
-                                     const vcl::ITextLayout* _pTextLayout) 
const
+                                     const vcl::TextLayoutCommon* 
_pTextLayout) const
 {
     return GetOutDev()->GetTextRect(rRect, rStr, nStyle, pInfo, _pTextLayout);
 }

Reply via email to