summaryrefslogtreecommitdiffstats
path: root/sw/source/core/txtnode/fntcap.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/txtnode/fntcap.cxx')
-rw-r--r--sw/source/core/txtnode/fntcap.cxx782
1 files changed, 782 insertions, 0 deletions
diff --git a/sw/source/core/txtnode/fntcap.cxx b/sw/source/core/txtnode/fntcap.cxx
new file mode 100644
index 000000000..a08988c45
--- /dev/null
+++ b/sw/source/core/txtnode/fntcap.cxx
@@ -0,0 +1,782 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/svxfont.hxx>
+
+#include <vcl/outdev.hxx>
+#include <com/sun/star/i18n/CharType.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+
+#include <fntcache.hxx>
+#include <swfont.hxx>
+#include <breakit.hxx>
+#include <txtfrm.hxx>
+#include <scriptinfo.hxx>
+#include <fntcap.hxx>
+
+using namespace ::com::sun::star::i18n;
+
+namespace {
+
+// The information encapsulated in SwCapitalInfo is required
+// by the ::Do functions. They contain the information about
+// the original string, whereas rDo.GetInf() contains information
+// about the display string.
+class SwCapitalInfo
+{
+public:
+ explicit SwCapitalInfo( const OUString& rOrigText ) :
+ rString( rOrigText ), nIdx( 0 ), nLen( 0 ) {};
+ const OUString& rString;
+ TextFrameIndex nIdx;
+ TextFrameIndex nLen;
+};
+
+}
+
+// rFnt: required for CalcCaseMap
+// rOrigString: The original string
+// nOfst: Position of the substring in rOrigString
+// nLen: Length if the substring in rOrigString
+// nIdx: Refers to a position in the display string and should be mapped
+// to a position in rOrigString
+TextFrameIndex sw_CalcCaseMap(const SwFont& rFnt,
+ const OUString& rOrigString,
+ TextFrameIndex const nOfst,
+ TextFrameIndex const nLen,
+ TextFrameIndex const nIdx)
+{
+ int j = 0;
+ const TextFrameIndex nEnd = nOfst + nLen;
+ OSL_ENSURE( sal_Int32(nEnd) <= rOrigString.getLength(), "sw_CalcCaseMap: Wrong parameters" );
+
+ // special case for title case:
+ const bool bTitle = SvxCaseMap::Capitalize == rFnt.GetCaseMap();
+ for (TextFrameIndex i = nOfst; i < nEnd; ++i)
+ {
+ OUString aTmp(rOrigString.copy(sal_Int32(i), 1));
+
+ if ( !bTitle ||
+ g_pBreakIt->GetBreakIter()->isBeginWord(
+ rOrigString, sal_Int32(i),
+ g_pBreakIt->GetLocale( rFnt.GetLanguage() ),
+ WordType::ANYWORD_IGNOREWHITESPACES ) )
+ aTmp = rFnt.GetActualFont().CalcCaseMap( aTmp );
+
+ j += aTmp.getLength();
+
+ if (TextFrameIndex(j) > nIdx)
+ return i;
+ }
+
+ return nOfst + nLen;
+}
+
+class SwDoCapitals
+{
+protected:
+ SwDrawTextInfo &m_rInf;
+ SwCapitalInfo* m_pCapInf; // refers to additional information
+ // required by the ::Do function
+ explicit SwDoCapitals ( SwDrawTextInfo &rInfo ) : m_rInf( rInfo ), m_pCapInf( nullptr ) { }
+ ~SwDoCapitals() {}
+public:
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) = 0;
+ virtual void Do() = 0;
+ OutputDevice& GetOut() { return m_rInf.GetOut(); }
+ SwDrawTextInfo& GetInf() { return m_rInf; }
+ SwCapitalInfo* GetCapInf() const { return m_pCapInf; }
+ void SetCapInf( SwCapitalInfo& rNew ) { m_pCapInf = &rNew; }
+};
+
+namespace {
+
+class SwDoGetCapitalSize : public SwDoCapitals
+{
+protected:
+ Size m_aTextSize;
+
+public:
+ explicit SwDoGetCapitalSize( SwDrawTextInfo &rInfo ) : SwDoCapitals ( rInfo ) { }
+ virtual ~SwDoGetCapitalSize() {}
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
+ virtual void Do() override;
+ const Size& GetSize() const { return m_aTextSize; }
+};
+
+}
+
+void SwDoGetCapitalSize::Init( SwFntObj *, SwFntObj * )
+{
+ m_aTextSize.setHeight(0);
+ m_aTextSize.setWidth(0);
+}
+
+void SwDoGetCapitalSize::Do()
+{
+ m_aTextSize.AdjustWidth(m_rInf.GetSize().Width());
+ if( m_rInf.GetUpper() )
+ m_aTextSize.setHeight(m_rInf.GetSize().Height());
+}
+
+Size SwSubFont::GetCapitalSize( SwDrawTextInfo& rInf )
+{
+ // Start:
+ const tools::Long nOldKern = rInf.GetKern();
+ rInf.SetKern( CheckKerning() );
+ rInf.SetPos( Point() );
+ rInf.SetSpace( 0 );
+ rInf.SetDrawSpace( false );
+ SwDoGetCapitalSize aDo( rInf );
+ DoOnCapitals( aDo );
+ Size aTextSize( aDo.GetSize() );
+
+ // End:
+ if( !aTextSize.Height() )
+ {
+ SV_STAT( nGetTextSize );
+ aTextSize.setHeight( short ( rInf.GetpOut()->GetTextHeight() ) );
+ }
+ rInf.SetKern( nOldKern );
+ return aTextSize;
+}
+
+namespace {
+
+class SwDoGetCapitalBreak : public SwDoCapitals
+{
+protected:
+ tools::Long m_nTextWidth;
+ TextFrameIndex m_nBreak;
+
+public:
+ SwDoGetCapitalBreak(SwDrawTextInfo& rInfo, tools::Long const nWidth)
+ : SwDoCapitals(rInfo)
+ , m_nTextWidth(nWidth)
+ , m_nBreak(-1)
+ { }
+ virtual ~SwDoGetCapitalBreak() {}
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
+ virtual void Do() override;
+ TextFrameIndex getBreak() const { return m_nBreak; }
+};
+
+}
+
+void SwDoGetCapitalBreak::Init( SwFntObj *, SwFntObj * )
+{
+}
+
+void SwDoGetCapitalBreak::Do()
+{
+ if (!m_nTextWidth)
+ return;
+
+ if (m_rInf.GetSize().Width() < m_nTextWidth)
+ m_nTextWidth -= m_rInf.GetSize().Width();
+ else
+ {
+ TextFrameIndex nEnd = m_rInf.GetEnd();
+ m_nBreak = TextFrameIndex(GetOut().GetTextBreak(m_rInf.GetText(), m_nTextWidth,
+ sal_Int32(m_rInf.GetIdx()),
+ sal_Int32(m_rInf.GetLen()), m_rInf.GetKern()));
+
+ if (m_nBreak > nEnd || m_nBreak < TextFrameIndex(0))
+ m_nBreak = nEnd;
+
+ // m_nBreak may be relative to the display string. It has to be
+ // calculated relative to the original string:
+ if ( GetCapInf() )
+ {
+ if ( GetCapInf()->nLen != m_rInf.GetLen() )
+ m_nBreak = sw_CalcCaseMap( *m_rInf.GetFont(),
+ GetCapInf()->rString,
+ GetCapInf()->nIdx,
+ GetCapInf()->nLen, m_nBreak );
+ else
+ m_nBreak = m_nBreak + GetCapInf()->nIdx;
+ }
+
+ m_nTextWidth = 0;
+ }
+}
+
+TextFrameIndex SwFont::GetCapitalBreak( SwViewShell const * pSh, const OutputDevice* pOut,
+ const SwScriptInfo* pScript, const OUString& rText, tools::Long const nTextWidth,
+ TextFrameIndex const nIdx, TextFrameIndex const nLen)
+{
+ // Start:
+ Point aPos( 0, 0 );
+ SwDrawTextInfo aInfo(pSh, *const_cast<OutputDevice*>(pOut), pScript, rText, nIdx, nLen,
+ 0, false);
+ aInfo.SetPos( aPos );
+ aInfo.SetSpace( 0 );
+ aInfo.SetWrong( nullptr );
+ aInfo.SetGrammarCheck( nullptr );
+ aInfo.SetSmartTags( nullptr );
+ aInfo.SetDrawSpace( false );
+ aInfo.SetKern( CheckKerning() );
+ aInfo.SetKanaComp( pScript ? 0 : 100 );
+ aInfo.SetFont( this );
+
+ SwDoGetCapitalBreak aDo(aInfo, nTextWidth);
+ DoOnCapitals( aDo );
+ return aDo.getBreak();
+}
+
+namespace {
+
+class SwDoDrawCapital : public SwDoCapitals
+{
+protected:
+ SwFntObj* m_pUpperFnt;
+ SwFntObj* m_pLowerFnt;
+
+public:
+ explicit SwDoDrawCapital(SwDrawTextInfo& rInfo)
+ : SwDoCapitals(rInfo)
+ , m_pUpperFnt(nullptr)
+ , m_pLowerFnt(nullptr)
+ { }
+ virtual ~SwDoDrawCapital() {}
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
+ virtual void Do() override;
+ void DrawSpace( Point &rPos );
+};
+
+}
+
+void SwDoDrawCapital::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
+{
+ m_pUpperFnt = pUpperFont;
+ m_pLowerFnt = pLowerFont;
+}
+
+void SwDoDrawCapital::Do()
+{
+ SV_STAT( nDrawText );
+ const sal_uInt16 nOrgWidth = m_rInf.GetWidth();
+ m_rInf.SetWidth( sal_uInt16(m_rInf.GetSize().Width()) );
+ if ( m_rInf.GetUpper() )
+ m_pUpperFnt->DrawText(m_rInf);
+ else
+ {
+ bool bOldBullet = m_rInf.GetBullet();
+ m_rInf.SetBullet( false );
+ m_pLowerFnt->DrawText(m_rInf);
+ m_rInf.SetBullet( bOldBullet );
+ }
+
+ OSL_ENSURE(m_pUpperFnt, "No upper font, dying soon!");
+ m_rInf.Shift(m_pUpperFnt->GetFont().GetOrientation());
+ m_rInf.SetWidth( nOrgWidth );
+}
+
+void SwDoDrawCapital::DrawSpace( Point &rPos )
+{
+ tools::Long nDiff = m_rInf.GetPos().X() - rPos.X();
+
+ Point aPos( rPos );
+ const bool bSwitchL2R = m_rInf.GetFrame()->IsRightToLeft() &&
+ ! m_rInf.IsIgnoreFrameRTL();
+
+ if ( bSwitchL2R )
+ m_rInf.GetFrame()->SwitchLTRtoRTL( aPos );
+
+ const vcl::text::ComplexTextLayoutFlags nMode = m_rInf.GetpOut()->GetLayoutMode();
+ const bool bBidiPor = ( bSwitchL2R !=
+ ( vcl::text::ComplexTextLayoutFlags::Default != ( vcl::text::ComplexTextLayoutFlags::BiDiRtl & nMode ) ) );
+
+ if ( bBidiPor )
+ nDiff = -nDiff;
+
+ if ( m_rInf.GetFrame()->IsVertical() )
+ m_rInf.GetFrame()->SwitchHorizontalToVertical( aPos );
+
+ if ( nDiff )
+ {
+ m_rInf.ApplyAutoColor();
+ GetOut().DrawStretchText( aPos, nDiff,
+ " ", 0, 2 );
+ }
+ rPos.setX( m_rInf.GetPos().X() + m_rInf.GetWidth() );
+}
+
+void SwSubFont::DrawCapital( SwDrawTextInfo &rInf )
+{
+ // Precondition: rInf.GetPos() has already been calculated
+
+ rInf.SetDrawSpace( GetUnderline() != LINESTYLE_NONE ||
+ GetOverline() != LINESTYLE_NONE ||
+ GetStrikeout() != STRIKEOUT_NONE );
+ SwDoDrawCapital aDo( rInf );
+ DoOnCapitals( aDo );
+}
+
+namespace {
+
+class SwDoCapitalCursorOfst : public SwDoCapitals
+{
+protected:
+ SwFntObj* m_pUpperFnt;
+ SwFntObj* m_pLowerFnt;
+ TextFrameIndex m_nCursor;
+ sal_uInt16 m_nOfst;
+
+public:
+ SwDoCapitalCursorOfst(SwDrawTextInfo& rInfo, const sal_uInt16 nOfs)
+ : SwDoCapitals(rInfo)
+ , m_pUpperFnt(nullptr)
+ , m_pLowerFnt(nullptr)
+ , m_nCursor(0)
+ , m_nOfst(nOfs)
+ { }
+ virtual ~SwDoCapitalCursorOfst() {}
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
+ virtual void Do() override;
+
+ TextFrameIndex GetCursor() const { return m_nCursor; }
+};
+
+}
+
+void SwDoCapitalCursorOfst::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
+{
+ m_pUpperFnt = pUpperFont;
+ m_pLowerFnt = pLowerFont;
+}
+
+void SwDoCapitalCursorOfst::Do()
+{
+ if (!m_nOfst)
+ return;
+
+ if (static_cast<tools::Long>(m_nOfst) > m_rInf.GetSize().Width())
+ {
+ m_nOfst -= m_rInf.GetSize().Width();
+ m_nCursor = m_nCursor + m_rInf.GetLen();
+ }
+ else
+ {
+ SwDrawTextInfo aDrawInf( m_rInf.GetShell(), *m_rInf.GetpOut(),
+ m_rInf.GetScriptInfo(),
+ m_rInf.GetText(),
+ m_rInf.GetIdx(),
+ m_rInf.GetLen(), 0, false );
+ aDrawInf.SetOffset(m_nOfst);
+ aDrawInf.SetKern( m_rInf.GetKern() );
+ aDrawInf.SetKanaComp( m_rInf.GetKanaComp() );
+ aDrawInf.SetFrame( m_rInf.GetFrame() );
+ aDrawInf.SetFont( m_rInf.GetFont() );
+
+ if ( m_rInf.GetUpper() )
+ {
+ aDrawInf.SetSpace( 0 );
+ m_nCursor = m_nCursor + m_pUpperFnt->GetModelPositionForViewPoint(aDrawInf);
+ }
+ else
+ {
+ aDrawInf.SetSpace( m_rInf.GetSpace() );
+ m_nCursor = m_nCursor + m_pLowerFnt->GetModelPositionForViewPoint(aDrawInf);
+ }
+ m_nOfst = 0;
+ }
+}
+
+TextFrameIndex SwSubFont::GetCapitalCursorOfst( SwDrawTextInfo& rInf )
+{
+ const tools::Long nOldKern = rInf.GetKern();
+ rInf.SetKern( CheckKerning() );
+ SwDoCapitalCursorOfst aDo( rInf, rInf.GetOffset() );
+ rInf.SetPos( Point() );
+ rInf.SetDrawSpace( false );
+ DoOnCapitals( aDo );
+ rInf.SetKern( nOldKern );
+ return aDo.GetCursor();
+}
+
+namespace {
+
+class SwDoDrawStretchCapital : public SwDoDrawCapital
+{
+ const TextFrameIndex m_nStrLen;
+ const sal_uInt16 m_nCapWidth;
+ const sal_uInt16 m_nOrgWidth;
+
+public:
+ virtual void Do() override;
+
+ SwDoDrawStretchCapital(SwDrawTextInfo& rInfo, const sal_uInt16 nCapitalWidth)
+ : SwDoDrawCapital(rInfo)
+ , m_nStrLen(rInfo.GetLen())
+ , m_nCapWidth(nCapitalWidth)
+ , m_nOrgWidth(rInfo.GetWidth())
+ { }
+};
+
+}
+
+void SwDoDrawStretchCapital::Do()
+{
+ SV_STAT( nDrawStretchText );
+ tools::Long nPartWidth = m_rInf.GetSize().Width();
+
+ if( m_rInf.GetLen() )
+ {
+ // small caps and kerning
+ tools::Long nDiff = tools::Long(m_nOrgWidth) - tools::Long(m_nCapWidth);
+ if( nDiff )
+ {
+ nDiff *= sal_Int32(m_rInf.GetLen());
+ nDiff /= sal_Int32(m_nStrLen);
+ nDiff += nPartWidth;
+ if( 0 < nDiff )
+ nPartWidth = nDiff;
+ }
+
+ m_rInf.ApplyAutoColor();
+
+ Point aPos( m_rInf.GetPos() );
+ const bool bSwitchL2R = m_rInf.GetFrame()->IsRightToLeft() &&
+ ! m_rInf.IsIgnoreFrameRTL();
+
+ if ( bSwitchL2R )
+ m_rInf.GetFrame()->SwitchLTRtoRTL( aPos );
+
+ if ( m_rInf.GetFrame()->IsVertical() )
+ m_rInf.GetFrame()->SwitchHorizontalToVertical( aPos );
+
+ // Optimise:
+ if (TextFrameIndex(1) >= m_rInf.GetLen())
+ GetOut().DrawText(aPos, m_rInf.GetText(), sal_Int32(m_rInf.GetIdx()),
+ sal_Int32(m_rInf.GetLen()));
+ else
+ GetOut().DrawStretchText(aPos, nPartWidth, m_rInf.GetText(),
+ sal_Int32(m_rInf.GetIdx()), sal_Int32(m_rInf.GetLen()));
+ }
+ const_cast<Point&>(m_rInf.GetPos()).AdjustX(nPartWidth );
+}
+
+void SwSubFont::DrawStretchCapital( SwDrawTextInfo &rInf )
+{
+ // Precondition: rInf.GetPos() has already been calculated
+
+ if (rInf.GetLen() == TextFrameIndex(COMPLETE_STRING))
+ rInf.SetLen(TextFrameIndex(rInf.GetText().getLength()));
+
+ const Point aOldPos = rInf.GetPos();
+ const sal_uInt16 nCapWidth = o3tl::narrowing<sal_uInt16>( GetCapitalSize( rInf ).Width() );
+ rInf.SetPos(aOldPos);
+
+ rInf.SetDrawSpace( GetUnderline() != LINESTYLE_NONE ||
+ GetOverline() != LINESTYLE_NONE ||
+ GetStrikeout() != STRIKEOUT_NONE );
+ SwDoDrawStretchCapital aDo( rInf, nCapWidth );
+ DoOnCapitals( aDo );
+}
+
+void SwSubFont::DoOnCapitals( SwDoCapitals &rDo )
+{
+ OSL_ENSURE( pLastFont, "SwFont::DoOnCapitals: No LastFont?!" );
+
+ tools::Long nKana = 0;
+ const OUString aText( CalcCaseMap( rDo.GetInf().GetText() ) );
+ TextFrameIndex nMaxPos = std::min(
+ TextFrameIndex(rDo.GetInf().GetText().getLength()) - rDo.GetInf().GetIdx(),
+ rDo.GetInf().GetLen() );
+ rDo.GetInf().SetLen( nMaxPos );
+
+ const OUString oldText = rDo.GetInf().GetText();
+ rDo.GetInf().SetText( aText );
+ TextFrameIndex nPos = rDo.GetInf().GetIdx();
+ TextFrameIndex nOldPos = nPos;
+ nMaxPos = nMaxPos + nPos;
+
+ // Look if the length of the original text and the ToUpper-converted
+ // text is different. If yes, do special handling.
+ SwCapitalInfo aCapInf(oldText);
+ bool bCaseMapLengthDiffers(aText.getLength() != oldText.getLength());
+ if ( bCaseMapLengthDiffers )
+ rDo.SetCapInf( aCapInf );
+
+ SwFntObj *pOldLast = pLastFont;
+ std::unique_ptr<SwFntAccess> pBigFontAccess;
+ SwFntObj *pBigFont;
+ std::unique_ptr<SwFntAccess> pSpaceFontAccess;
+ SwFntObj *pSpaceFont = nullptr;
+
+ const void* nFontCacheId2 = nullptr;
+ sal_uInt16 nIndex2 = 0;
+ SwSubFont aFont( *this );
+ Point aStartPos( rDo.GetInf().GetPos() );
+
+ const bool bTextLines = aFont.GetUnderline() != LINESTYLE_NONE
+ || aFont.GetOverline() != LINESTYLE_NONE
+ || aFont.GetStrikeout() != STRIKEOUT_NONE;
+ const bool bWordWise = bTextLines && aFont.IsWordLineMode() &&
+ rDo.GetInf().GetDrawSpace();
+ const tools::Long nTmpKern = rDo.GetInf().GetKern();
+
+ if ( bTextLines )
+ {
+ if ( bWordWise )
+ {
+ aFont.SetWordLineMode( false );
+ pSpaceFontAccess.reset(new SwFntAccess( nFontCacheId2, nIndex2, &aFont,
+ rDo.GetInf().GetShell() ));
+ pSpaceFont = pSpaceFontAccess->Get();
+ }
+ else
+ pSpaceFont = pLastFont;
+
+ // Construct a font for the capitals:
+ aFont.SetUnderline( LINESTYLE_NONE );
+ aFont.SetOverline( LINESTYLE_NONE );
+ aFont.SetStrikeout( STRIKEOUT_NONE );
+ nFontCacheId2 = nullptr;
+ nIndex2 = 0;
+ pBigFontAccess.reset(new SwFntAccess( nFontCacheId2, nIndex2, &aFont,
+ rDo.GetInf().GetShell() ));
+ pBigFont = pBigFontAccess->Get();
+ }
+ else
+ pBigFont = pLastFont;
+
+ // Older LO versions had 66 as the small caps percentage size, later changed to 80,
+ // therefore a backwards compatibility option is kept (otherwise layout is changed).
+ // NOTE: There are more uses of SMALL_CAPS_PERCENTAGE in editeng, but it seems they
+ // do not matter for Writer (and if they did it'd be pretty ugly to propagate
+ // the option there).
+ int smallCapsPercentage = m_bSmallCapsPercentage66 ? 66 : SMALL_CAPS_PERCENTAGE;
+ aFont.SetProportion( (aFont.GetPropr() * smallCapsPercentage ) / 100 );
+ nFontCacheId2 = nullptr;
+ nIndex2 = 0;
+ std::unique_ptr<SwFntAccess> pSmallFontAccess( new SwFntAccess( nFontCacheId2, nIndex2, &aFont,
+ rDo.GetInf().GetShell() ));
+ SwFntObj *pSmallFont = pSmallFontAccess->Get();
+
+ rDo.Init( pBigFont, pSmallFont );
+ OutputDevice* pOutSize = pSmallFont->GetPrt();
+ if( !pOutSize )
+ pOutSize = &rDo.GetOut();
+ OutputDevice* pOldOut = &rDo.GetOut();
+
+ const LanguageType eLng = LANGUAGE_DONTKNOW == GetLanguage()
+ ? LANGUAGE_SYSTEM : GetLanguage();
+
+ if( nPos < nMaxPos )
+ {
+ nPos = TextFrameIndex(g_pBreakIt->GetBreakIter()->endOfCharBlock(
+ oldText, sal_Int32(nPos),
+ g_pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER));
+ if (nPos < TextFrameIndex(0))
+ nPos = nOldPos;
+ else if( nPos > nMaxPos )
+ nPos = nMaxPos;
+ }
+
+ while( nOldPos < nMaxPos )
+ {
+
+ // The lower ones...
+ if( nOldPos != nPos )
+ {
+ SV_STAT( nGetTextSize );
+ pLastFont = pSmallFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+
+ // #107816#, #i14820#
+ if( bCaseMapLengthDiffers )
+ {
+ // Build an own 'changed' string for the given part of the
+ // source string and use it. That new string may differ in length
+ // from the source string.
+ const OUString aNewText = CalcCaseMap(
+ oldText.copy(sal_Int32(nOldPos), sal_Int32(nPos-nOldPos)));
+ aCapInf.nIdx = nOldPos;
+ aCapInf.nLen = nPos - nOldPos;
+ rDo.GetInf().SetTextIdxLen(aNewText, TextFrameIndex(0), TextFrameIndex(aNewText.getLength()));
+ }
+ else
+ {
+ rDo.GetInf().SetIdxLen(nOldPos, nPos - nOldPos);
+ }
+
+ rDo.GetInf().SetUpper( false );
+ rDo.GetInf().SetOut( *pOutSize );
+ Size aPartSize = pSmallFont->GetTextSize( rDo.GetInf() );
+ nKana += rDo.GetInf().GetKanaDiff();
+ rDo.GetInf().SetOut( *pOldOut );
+ if( nTmpKern && nPos < nMaxPos )
+ aPartSize.AdjustWidth(nTmpKern );
+ rDo.GetInf().SetSize( aPartSize );
+ rDo.Do();
+ nOldPos = nPos;
+ }
+ nPos = TextFrameIndex(g_pBreakIt->GetBreakIter()->nextCharBlock(
+ oldText, sal_Int32(nPos),
+ g_pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER));
+ if (nPos < TextFrameIndex(0) || nPos > nMaxPos)
+ nPos = nMaxPos;
+ OSL_ENSURE( nPos, "nextCharBlock not implemented?" );
+#if OSL_DEBUG_LEVEL > 1
+ if( !nPos )
+ nPos = nMaxPos;
+#endif
+ // The upper ones...
+ if( nOldPos != nPos )
+ {
+ const tools::Long nSpaceAdd = rDo.GetInf().GetSpace() / SPACING_PRECISION_FACTOR;
+
+ do
+ {
+ rDo.GetInf().SetUpper( true );
+ pLastFont = pBigFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+ TextFrameIndex nTmp;
+ if( bWordWise )
+ {
+ nTmp = nOldPos;
+ while (nTmp < nPos && CH_BLANK == oldText[sal_Int32(nTmp)])
+ ++nTmp;
+ if( nOldPos < nTmp )
+ {
+ pLastFont = pSpaceFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(),
+ rDo.GetOut() );
+ static_cast<SwDoDrawCapital&>(rDo).DrawSpace( aStartPos );
+ pLastFont = pBigFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(),
+ rDo.GetOut() );
+
+ // #107816#, #i14820#
+ if( bCaseMapLengthDiffers )
+ {
+ // Build an own 'changed' string for the given part of the
+ // source string and use it. That new string may differ in length
+ // from the source string.
+ const OUString aNewText = CalcCaseMap(
+ oldText.copy(sal_Int32(nOldPos), sal_Int32(nTmp-nOldPos)));
+ aCapInf.nIdx = nOldPos;
+ aCapInf.nLen = nTmp - nOldPos;
+ rDo.GetInf().SetIdx(TextFrameIndex(0));
+ rDo.GetInf().SetLen(TextFrameIndex(aNewText.getLength()));
+ rDo.GetInf().SetText( aNewText );
+ }
+ else
+ {
+ rDo.GetInf().SetIdx( nOldPos );
+ rDo.GetInf().SetLen( nTmp - nOldPos );
+ }
+
+ rDo.GetInf().SetOut( *pOutSize );
+ Size aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
+ nKana += rDo.GetInf().GetKanaDiff();
+ rDo.GetInf().SetOut( *pOldOut );
+ if( nSpaceAdd )
+ aPartSize.AdjustWidth(nSpaceAdd * sal_Int32(nTmp - nOldPos));
+ if( nTmpKern && nPos < nMaxPos )
+ aPartSize.AdjustWidth(nTmpKern );
+ rDo.GetInf().SetSize( aPartSize );
+ rDo.Do();
+ aStartPos = rDo.GetInf().GetPos();
+ nOldPos = nTmp;
+ }
+
+ while (nTmp < nPos && CH_BLANK != oldText[sal_Int32(nTmp)])
+ ++nTmp;
+ }
+ else
+ nTmp = nPos;
+ if( nTmp > nOldPos )
+ {
+ // #107816#, #i14820#
+ if( bCaseMapLengthDiffers )
+ {
+ // Build an own 'changed' string for the given part of the
+ // source string and use it. That new string may differ in length
+ // from the source string.
+ const OUString aNewText = CalcCaseMap(
+ oldText.copy(sal_Int32(nOldPos), sal_Int32(nTmp-nOldPos)));
+ aCapInf.nIdx = nOldPos;
+ aCapInf.nLen = nTmp - nOldPos;
+ rDo.GetInf().SetTextIdxLen( aNewText, TextFrameIndex(0), TextFrameIndex(aNewText.getLength()));
+ }
+ else
+ {
+ rDo.GetInf().SetIdxLen( nOldPos, nTmp - nOldPos );
+ }
+
+ rDo.GetInf().SetOut( *pOutSize );
+ Size aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
+ nKana += rDo.GetInf().GetKanaDiff();
+ rDo.GetInf().SetOut( *pOldOut );
+ if( !bWordWise && rDo.GetInf().GetSpace() )
+ {
+ for (TextFrameIndex nI = nOldPos; nI < nPos; ++nI)
+ {
+ if (CH_BLANK == oldText[sal_Int32(nI)])
+ aPartSize.AdjustWidth(nSpaceAdd );
+ }
+ }
+ if( nTmpKern && nPos < nMaxPos )
+ aPartSize.AdjustWidth(nTmpKern );
+ rDo.GetInf().SetSize( aPartSize );
+ rDo.Do();
+ nOldPos = nTmp;
+ }
+ } while( nOldPos != nPos );
+ }
+ nPos = TextFrameIndex(g_pBreakIt->GetBreakIter()->endOfCharBlock(
+ oldText, sal_Int32(nPos),
+ g_pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER));
+ if (nPos < TextFrameIndex(0) || nPos > nMaxPos)
+ nPos = nMaxPos;
+ OSL_ENSURE( nPos, "endOfCharBlock not implemented?" );
+#if OSL_DEBUG_LEVEL > 1
+ if( !nPos )
+ nPos = nMaxPos;
+#endif
+ }
+
+ // clean up:
+ if( pBigFont != pOldLast )
+ pBigFontAccess.reset();
+
+ if( bTextLines )
+ {
+ if( rDo.GetInf().GetDrawSpace() )
+ {
+ pLastFont = pSpaceFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+ static_cast<SwDoDrawCapital&>( rDo ).DrawSpace( aStartPos );
+ }
+ if ( bWordWise )
+ pSpaceFontAccess.reset();
+ }
+ pLastFont = pOldLast;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+
+ pSmallFontAccess.reset();
+ rDo.GetInf().SetText(oldText);
+ rDo.GetInf().SetKanaDiff( nKana );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */