diff options
Diffstat (limited to 'sw/source/core/txtnode/fntcap.cxx')
-rw-r--r-- | sw/source/core/txtnode/fntcap.cxx | 782 |
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: */ |