/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"


#include <hintids.hxx>
#include <editeng/cmapitem.hxx>

#ifndef _OUTDEV_HXX //autogen
#include <vcl/outdev.hxx>
#endif
#ifndef _COM_SUN_STAR_I18N_CHARTYPE_HDL
#include <com/sun/star/i18n/CharType.hdl>
#endif
#ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
#include <com/sun/star/i18n/WordType.hdl>
#endif

#ifndef _PRINT_HXX //autogen
#include <vcl/print.hxx>
#endif
#include <errhdl.hxx>
#include <fntcache.hxx>
#include <swfont.hxx>
#include <breakit.hxx>
#include <txtfrm.hxx>       // SwTxtFrm
#include <scriptinfo.hxx>

using namespace ::com::sun::star::i18n;


#define KAPITAELCHENPROP 74

/*************************************************************************
 *						class SwCapitalInfo
 *
 * 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 XubString& rOrigText ) :
        rString( rOrigText ), nIdx( 0 ), nLen( 0 ) {};
    const XubString& rString;
    xub_StrLen nIdx;
    xub_StrLen nLen;
};

/*************************************************************************
 *						xub_StrLen lcl_CalcCaseMap()
 *
 * rFnt: required for CalcCaseMap
 * rOrigString: The original string
 * nOfst: Position of the substring in rOrigString
 * nLen: Length if the substring in rOrigString
 * nIdx: Referes to a position in the display string and should be mapped
 *       to a position in rOrigString
 *************************************************************************/

xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt,
                            const XubString& rOrigString,
                            xub_StrLen nOfst,
                            xub_StrLen nLen,
                            xub_StrLen nIdx )
{
    int j = 0;
    const xub_StrLen nEnd = nOfst + nLen;
    ASSERT( nEnd <= rOrigString.Len(), "lcl_CalcCaseMap: Wrong parameters" )

    // special case for title case:
    const bool bTitle = SVX_CASEMAP_TITEL == rFnt.GetCaseMap() &&
                        pBreakIt->GetBreakIter().is();
    for ( xub_StrLen i = nOfst; i < nEnd; ++i )
    {
        XubString aTmp( rOrigString, i, 1 );

        if ( !bTitle ||
             pBreakIt->GetBreakIter()->isBeginWord(
                 rOrigString, i,
                 pBreakIt->GetLocale( rFnt.GetLanguage() ),
                 WordType::ANYWORD_IGNOREWHITESPACES ) )
            aTmp = rFnt.GetActualFont().CalcCaseMap( aTmp );

        j += aTmp.Len();

        if ( j > nIdx )
            return i;
    }

    return nOfst + nLen;
}

/*************************************************************************
 *						class SwDoCapitals
 *************************************************************************/

class SwDoCapitals
{
protected:
	SwDrawTextInfo &rInf;
    SwCapitalInfo* pCapInf; // referes to additional information
                           // required by the ::Do function
public:
    SwDoCapitals ( SwDrawTextInfo &rInfo ) : rInf( rInfo ), pCapInf( 0 ) { }
	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) = 0;
	virtual void Do() = 0;
    inline OutputDevice& GetOut() { return rInf.GetOut(); }
	inline SwDrawTextInfo& GetInf() { return rInf; }
    inline SwCapitalInfo* GetCapInf() const { return pCapInf; }
    inline void SetCapInf( SwCapitalInfo& rNew ) { pCapInf = &rNew; }
};

/*************************************************************************
 *					  class SwDoGetCapitalSize
 *************************************************************************/

class SwDoGetCapitalSize : public SwDoCapitals
{
protected:
	Size aTxtSize;
public:
	SwDoGetCapitalSize( SwDrawTextInfo &rInfo ) : SwDoCapitals ( rInfo ) { }
	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
	virtual void Do();
	const Size &GetSize() const { return aTxtSize; }
};

void SwDoGetCapitalSize::Init( SwFntObj *, SwFntObj * )
{
	aTxtSize.Height() = 0;
	aTxtSize.Width() = 0;
}

void SwDoGetCapitalSize::Do()
{
	aTxtSize.Width() += rInf.GetSize().Width();
	if( rInf.GetUpper() )
		aTxtSize.Height() = rInf.GetSize().Height();
}

/*************************************************************************
 *					  SwSubFont::GetCapitalSize()
 *************************************************************************/

Size SwSubFont::GetCapitalSize( SwDrawTextInfo& rInf )
{
	// Start:
    const long nOldKern = rInf.GetKern();
	rInf.SetKern( CheckKerning() );
	Point aPos;
	rInf.SetPos( aPos );
	rInf.SetSpace( 0 );
	rInf.SetDrawSpace( sal_False );
	SwDoGetCapitalSize aDo( rInf );
	DoOnCapitals( aDo );
	Size aTxtSize( aDo.GetSize() );

	// End:
	if( !aTxtSize.Height() )
	{
		SV_STAT( nGetTextSize );
		aTxtSize.Height() = short ( rInf.GetpOut()->GetTextHeight() );
	}
	rInf.SetKern( nOldKern );
	return aTxtSize;
}

/*************************************************************************
 *					  class SwDoGetCapitalBreak
 *************************************************************************/

class SwDoGetCapitalBreak : public SwDoCapitals
{
protected:
	xub_StrLen *pExtraPos;
	long nTxtWidth;
	xub_StrLen nBreak;
public:
	SwDoGetCapitalBreak( SwDrawTextInfo &rInfo, long nWidth, xub_StrLen *pExtra)
        :   SwDoCapitals ( rInfo ), pExtraPos( pExtra ), nTxtWidth( nWidth ),
            nBreak( STRING_LEN )
		{ }
	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
	virtual void Do();
	xub_StrLen GetBreak() const { return nBreak; }
};

void SwDoGetCapitalBreak::Init( SwFntObj *, SwFntObj * )
{
}

void SwDoGetCapitalBreak::Do()
{
	if ( nTxtWidth )
	{
		if ( rInf.GetSize().Width() < nTxtWidth )
			nTxtWidth -= rInf.GetSize().Width();
		else
		{
			xub_StrLen nEnd = rInf.GetEnd();
			if( pExtraPos )
			{
                nBreak = GetOut().GetTextBreak( rInf.GetText(), nTxtWidth, '-',
					 *pExtraPos, rInf.GetIdx(), rInf.GetLen(), rInf.GetKern() );
				if( *pExtraPos > nEnd )
					*pExtraPos = nEnd;
			}
			else
                nBreak = GetOut().GetTextBreak( rInf.GetText(), nTxtWidth,
							   rInf.GetIdx(), rInf.GetLen(), rInf.GetKern() );

			if( nBreak > nEnd )
				nBreak = nEnd;

            // nBreak may be relative to the display string. It has to be
            // calculated relative to the original string:
            if ( GetCapInf()  )
            {
                if ( GetCapInf()->nLen != rInf.GetLen() )
                    nBreak = lcl_CalcCaseMap( *rInf.GetFont(),
                                              GetCapInf()->rString,
                                              GetCapInf()->nIdx,
                                              GetCapInf()->nLen, nBreak );
                else
                    nBreak = nBreak + GetCapInf()->nIdx;
            }

			nTxtWidth = 0;
		}
	}
}

/*************************************************************************
 *					  SwFont::GetCapitalBreak()
 *************************************************************************/

xub_StrLen SwFont::GetCapitalBreak( ViewShell* pSh, const OutputDevice* pOut,
    const SwScriptInfo* pScript, const XubString& rTxt, long nTextWidth,
	xub_StrLen *pExtra,	const xub_StrLen nIdx, const xub_StrLen nLen )
{
	// Start:
	Point aPos( 0, 0 );
	SwDrawTextInfo aInfo(pSh, *(OutputDevice*)pOut, pScript, rTxt, nIdx, nLen,
		0, sal_False);
	aInfo.SetPos( aPos );
	aInfo.SetSpace( 0 );
	aInfo.SetWrong( NULL );
    aInfo.SetGrammarCheck( NULL );
    aInfo.SetSmartTags( NULL ); // SMARTTAGS
    aInfo.SetDrawSpace( sal_False );
	aInfo.SetKern( CheckKerning() );
	aInfo.SetKanaComp( pScript ? 0 : 100 );
    aInfo.SetFont( this );

	SwDoGetCapitalBreak aDo( aInfo, nTextWidth, pExtra );
	DoOnCapitals( aDo );
	return aDo.GetBreak();
}

/*************************************************************************
 *					   class SwDoDrawCapital
 *************************************************************************/

class SwDoDrawCapital : public SwDoCapitals
{
protected:
	SwFntObj *pUpperFnt;
	SwFntObj *pLowerFnt;
public:
	SwDoDrawCapital( SwDrawTextInfo &rInfo ) :
		SwDoCapitals( rInfo )
		{ }
	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
	virtual void Do();
	void DrawSpace( Point &rPos );
};

void SwDoDrawCapital::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
{
	pUpperFnt = pUpperFont;
	pLowerFnt = pLowerFont;
}

void SwDoDrawCapital::Do()
{
	SV_STAT( nDrawText );
	sal_uInt16 nOrgWidth = rInf.GetWidth();
	rInf.SetWidth( sal_uInt16(rInf.GetSize().Width()) );
	if ( rInf.GetUpper() )
		pUpperFnt->DrawText( rInf );
	else
	{
		sal_Bool bOldBullet = rInf.GetBullet();
		rInf.SetBullet( sal_False );
		pLowerFnt->DrawText( rInf );
		rInf.SetBullet( bOldBullet );
	}

    ASSERT( pUpperFnt, "No upper font, dying soon!");
    rInf.Shift( pUpperFnt->GetFont()->GetOrientation() );
	rInf.SetWidth( nOrgWidth );
}

/*************************************************************************
 *					  SwDoDrawCapital::DrawSpace()
 *************************************************************************/

void SwDoDrawCapital::DrawSpace( Point &rPos )
{
	static sal_Char __READONLY_DATA sDoubleSpace[] = "  ";

    long nDiff = rInf.GetPos().X() - rPos.X();

    Point aPos( rPos );
    const sal_Bool bSwitchL2R = rInf.GetFrm()->IsRightToLeft() &&
                          ! rInf.IsIgnoreFrmRTL();


    if ( bSwitchL2R )
       rInf.GetFrm()->SwitchLTRtoRTL( aPos );

    const sal_uLong nMode = rInf.GetpOut()->GetLayoutMode();
    const sal_Bool bBidiPor = ( bSwitchL2R !=
                            ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) );

    if ( bBidiPor )
        nDiff = -nDiff;

    if ( rInf.GetFrm()->IsVertical() )
        rInf.GetFrm()->SwitchHorizontalToVertical( aPos );

	if ( nDiff )
    {
        rInf.ApplyAutoColor();
        GetOut().DrawStretchText( aPos, nDiff,
			XubString( sDoubleSpace, RTL_TEXTENCODING_MS_1252 ), 0, 2 );
    }
	rPos.X() = rInf.GetPos().X() + rInf.GetWidth();
}

/*************************************************************************
 *					  SwSubFont::DrawCapital()
 *************************************************************************/

void SwSubFont::DrawCapital( SwDrawTextInfo &rInf )
{
	// Es wird vorausgesetzt, dass rPos bereits kalkuliert ist!
	// hochgezogen in SwFont: const Point aPos( CalcPos(rPos) );
	rInf.SetDrawSpace( GetUnderline() != UNDERLINE_NONE ||
					   GetOverline()  != UNDERLINE_NONE ||
					   GetStrikeout() != STRIKEOUT_NONE );
	SwDoDrawCapital aDo( rInf );
	DoOnCapitals( aDo );
}

/*************************************************************************
 *					   class SwDoDrawCapital
 *************************************************************************/

class SwDoCapitalCrsrOfst : public SwDoCapitals
{
protected:
	SwFntObj *pUpperFnt;
	SwFntObj *pLowerFnt;
	xub_StrLen nCrsr;
	sal_uInt16 nOfst;
public:
	SwDoCapitalCrsrOfst( SwDrawTextInfo &rInfo, const sal_uInt16 nOfs ) :
        SwDoCapitals( rInfo ), nCrsr( 0 ), nOfst( nOfs )
		{ }
	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
	virtual void Do();

	void DrawSpace( const Point &rPos );
	inline xub_StrLen GetCrsr(){ return nCrsr; }
};

void SwDoCapitalCrsrOfst::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
{
	pUpperFnt = pUpperFont;
	pLowerFnt = pLowerFont;
}

void SwDoCapitalCrsrOfst::Do()
{
	if ( nOfst )
	{
		if ( nOfst > rInf.GetSize().Width() )
		{
			nOfst = nOfst - sal_uInt16(rInf.GetSize().Width());
			nCrsr = nCrsr + rInf.GetLen();
		}
		else
		{
            SwDrawTextInfo aDrawInf( rInf.GetShell(), *rInf.GetpOut(),
                                     rInf.GetScriptInfo(),
                                     rInf.GetText(),
                                     rInf.GetIdx(),
                                     rInf.GetLen(), 0, sal_False );
            aDrawInf.SetOfst( nOfst );
            aDrawInf.SetKern( rInf.GetKern() );
            aDrawInf.SetKanaComp( rInf.GetKanaComp() );
            aDrawInf.SetFrm( rInf.GetFrm() );
            aDrawInf.SetFont( rInf.GetFont() );

			if ( rInf.GetUpper() )
            {
                aDrawInf.SetSpace( 0 );
                nCrsr = nCrsr + pUpperFnt->GetCrsrOfst( aDrawInf );
            }
			else
            {
                aDrawInf.SetSpace( rInf.GetSpace() );
                nCrsr = nCrsr + pLowerFnt->GetCrsrOfst( aDrawInf );
            }
            nOfst = 0;
		}
	}
}

/*************************************************************************
 *					  SwSubFont::GetCapitalCrsrOfst()
 *************************************************************************/

xub_StrLen SwSubFont::GetCapitalCrsrOfst( SwDrawTextInfo& rInf )
{
    const long nOldKern = rInf.GetKern();
	rInf.SetKern( CheckKerning() );
	SwDoCapitalCrsrOfst aDo( rInf, rInf.GetOfst() );
	Point aPos;
	rInf.SetPos( aPos );
	rInf.SetDrawSpace( sal_False );
	DoOnCapitals( aDo );
	rInf.SetKern( nOldKern );
	return aDo.GetCrsr();
}

/*************************************************************************
 *					  class SwDoDrawStretchCapital
 *************************************************************************/

class SwDoDrawStretchCapital : public SwDoDrawCapital
{
	const xub_StrLen nStrLen;
	const sal_uInt16 nCapWidth;
	const sal_uInt16 nOrgWidth;
public:
	virtual void Do();

    SwDoDrawStretchCapital( SwDrawTextInfo &rInfo, const sal_uInt16 nCapitalWidth )
			: SwDoDrawCapital( rInfo ),
              nStrLen( rInfo.GetLen() ),
              nCapWidth( nCapitalWidth ),
              nOrgWidth( rInfo.GetWidth() )
        { }
};

/*************************************************************************
 *					  SwDoDrawStretchCapital
 *************************************************************************/

void SwDoDrawStretchCapital::Do()
{
	SV_STAT( nDrawStretchText );
	sal_uInt16 nPartWidth = sal_uInt16(rInf.GetSize().Width());

	if( rInf.GetLen() )
	{
		// 4023: Kapitaelchen und Kerning.
		long nDiff = long(nOrgWidth) - long(nCapWidth);
		if( nDiff )
		{
			nDiff *= rInf.GetLen();
			nDiff /= (long) nStrLen;
			nDiff += nPartWidth;
			if( 0 < nDiff )
				nPartWidth = sal_uInt16(nDiff);
		}

        rInf.ApplyAutoColor();

        Point aPos( rInf.GetPos() );
        const sal_Bool bSwitchL2R = rInf.GetFrm()->IsRightToLeft() &&
                              ! rInf.IsIgnoreFrmRTL();

        if ( bSwitchL2R )
            rInf.GetFrm()->SwitchLTRtoRTL( aPos );

        if ( rInf.GetFrm()->IsVertical() )
            rInf.GetFrm()->SwitchHorizontalToVertical( aPos );

        // Optimierung:
        if( 1 >= rInf.GetLen() )
            GetOut().DrawText( aPos, rInf.GetText(), rInf.GetIdx(),
				rInf.GetLen() );
		else
            GetOut().DrawStretchText( aPos, nPartWidth,
								rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
	}
	((Point&)rInf.GetPos()).X() += nPartWidth;
}

/*************************************************************************
 *					  SwSubFont::DrawStretchCapital()
 *************************************************************************/

void SwSubFont::DrawStretchCapital( SwDrawTextInfo &rInf )
{
	// Es wird vorausgesetzt, dass rPos bereits kalkuliert ist!
	// hochgezogen in SwFont: const Point aPos( CalcPos(rPos) );

	if( rInf.GetLen() == STRING_LEN )
		rInf.SetLen( rInf.GetText().Len() );

    const Point& rOldPos = rInf.GetPos();
	const sal_uInt16 nCapWidth = (sal_uInt16)( GetCapitalSize( rInf ).Width() );
    rInf.SetPos( rOldPos );

	rInf.SetDrawSpace( GetUnderline() != UNDERLINE_NONE ||
					   GetOverline()  != UNDERLINE_NONE ||
					   GetStrikeout() != STRIKEOUT_NONE );
	SwDoDrawStretchCapital aDo( rInf, nCapWidth );
	DoOnCapitals( aDo );
}

/*************************************************************************
 *					SwSubFont::DoOnCapitals() const
 *************************************************************************/

// JP 22.8.2001 - global optimization off - Bug 91245 / 91223
#ifdef _MSC_VER
#pragma optimize("g",off)
#endif

void SwSubFont::DoOnCapitals( SwDoCapitals &rDo )
{
	ASSERT( pLastFont, "SwFont::DoOnCapitals: No LastFont?!" );

	Size aPartSize;
	long nKana = 0;
	const XubString aTxt( CalcCaseMap( rDo.GetInf().GetText() ) );
	xub_StrLen nMaxPos = Min( sal_uInt16(rDo.GetInf().GetText().Len()
							- rDo.GetInf().GetIdx()), rDo.GetInf().GetLen() );
	rDo.GetInf().SetLen( nMaxPos );

	const XubString& rOldText = rDo.GetInf().GetText();
	rDo.GetInf().SetText( aTxt );
	rDo.GetInf().SetSize( aPartSize );
	xub_StrLen nPos = rDo.GetInf().GetIdx();
	xub_StrLen nOldPos = nPos;
	nMaxPos = nMaxPos + nPos;

	// #107816#
	// Look if the length of the original text and the ToUpper-converted
	// text is different. If yes, do special handling.
    XubString aNewText;
    SwCapitalInfo aCapInf( rOldText );
    sal_Bool bCaseMapLengthDiffers( aTxt.Len() != rOldText.Len() );
    if ( bCaseMapLengthDiffers )
        rDo.SetCapInf( aCapInf );

	SwFntObj *pOldLast = pLastFont;
	SwFntAccess *pBigFontAccess = NULL;
	SwFntObj *pBigFont;
	SwFntAccess *pSpaceFontAccess = NULL;
	SwFntObj *pSpaceFont = NULL;

	const void *pMagic2 = NULL;
	sal_uInt16 nIndex2 = 0;
	SwSubFont aFont( *this );
	Point aStartPos( rDo.GetInf().GetPos() );

	const sal_Bool bTextLines = aFont.GetUnderline() != UNDERLINE_NONE
						 || aFont.GetOverline()  != UNDERLINE_NONE
						 || aFont.GetStrikeout() != STRIKEOUT_NONE;
	const sal_Bool bWordWise = bTextLines && aFont.IsWordLineMode() &&
						   rDo.GetInf().GetDrawSpace();
    const long nTmpKern = rDo.GetInf().GetKern();

	if ( bTextLines )
	{
		if ( bWordWise )
		{
			aFont.SetWordLineMode( sal_False );
			pSpaceFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
												rDo.GetInf().GetShell() );
			pSpaceFont = pSpaceFontAccess->Get();
		}
		else
			pSpaceFont = pLastFont;

		// Wir basteln uns einen Font fuer die Grossbuchstaben:
		aFont.SetUnderline( UNDERLINE_NONE );
		aFont.SetOverline( UNDERLINE_NONE );
		aFont.SetStrikeout( STRIKEOUT_NONE );
		pMagic2 = NULL;
		nIndex2 = 0;
		pBigFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
										  rDo.GetInf().GetShell() );
		pBigFont = pBigFontAccess->Get();
	}
	else
		pBigFont = pLastFont;

	// Hier entsteht der Kleinbuchstabenfont:
	aFont.SetProportion( sal_uInt8( (aFont.GetPropr()*KAPITAELCHENPROP) / 100L) );
	pMagic2 = NULL;
	nIndex2 = 0;
	SwFntAccess *pSmallFontAccess = new SwFntAccess( pMagic2, 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 = (xub_StrLen)pBreakIt->GetBreakIter()->endOfCharBlock( rOldText, nPos,
			pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
		if( nPos == STRING_LEN )
			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 XubString aSnippet( rOldText, nOldPos, nPos - nOldPos);
                aNewText = CalcCaseMap( aSnippet );
                aCapInf.nIdx = nOldPos;
                aCapInf.nLen = nPos - nOldPos;
                rDo.GetInf().SetIdx( 0 );
                rDo.GetInf().SetLen( aNewText.Len() );
                rDo.GetInf().SetText( aNewText );
            }
            else
            {
                rDo.GetInf().SetIdx( nOldPos );
                rDo.GetInf().SetLen( nPos - nOldPos );
            }

			rDo.GetInf().SetUpper( sal_False );
			rDo.GetInf().SetOut( *pOutSize );
			aPartSize = pSmallFont->GetTextSize( rDo.GetInf() );
			nKana += rDo.GetInf().GetKanaDiff();
			rDo.GetInf().SetOut( *pOldOut );
            if( nTmpKern && nPos < nMaxPos )
                aPartSize.Width() += nTmpKern;
			rDo.Do();
			nOldPos = nPos;
		}
		nPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharBlock( rOldText, nPos,
			   pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
		if( nPos == STRING_LEN || nPos > nMaxPos )
			nPos = nMaxPos;
		ASSERT( nPos, "nextCharBlock not implemented?" );
#ifdef DBG_UTIL
		if( !nPos )
			nPos = nMaxPos;
#endif
		// The upper ones...
		if( nOldPos != nPos )
		{
            const long nSpaceAdd = rDo.GetInf().GetSpace() / SPACING_PRECISION_FACTOR;

            do
			{
				rDo.GetInf().SetUpper( sal_True );
				pLastFont = pBigFont;
				pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
				xub_StrLen nTmp;
				if( bWordWise )
				{
					nTmp = nOldPos;
					while( nTmp < nPos && CH_BLANK == rOldText.GetChar( nTmp ) )
						++nTmp;
					if( nOldPos < nTmp )
					{
						pLastFont = pSpaceFont;
						pLastFont->SetDevFont( rDo.GetInf().GetShell(),
											   rDo.GetOut() );
						((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 XubString aSnippet( rOldText, nOldPos, nTmp - nOldPos);
                            aNewText = CalcCaseMap( aSnippet );
                            aCapInf.nIdx = nOldPos;
                            aCapInf.nLen = nTmp - nOldPos;
                            rDo.GetInf().SetIdx( 0 );
                            rDo.GetInf().SetLen( aNewText.Len() );
                            rDo.GetInf().SetText( aNewText );
                        }
                        else
                        {
                            rDo.GetInf().SetIdx( nOldPos );
                            rDo.GetInf().SetLen( nTmp - nOldPos );
                        }

						rDo.GetInf().SetOut( *pOutSize );
						aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
						nKana += rDo.GetInf().GetKanaDiff();
						rDo.GetInf().SetOut( *pOldOut );
                        if( nSpaceAdd )
                            aPartSize.Width() += nSpaceAdd * ( nTmp - nOldPos );
                        if( nTmpKern && nPos < nMaxPos )
                            aPartSize.Width() += nTmpKern;
						rDo.Do();
						aStartPos = rDo.GetInf().GetPos();
						nOldPos = nTmp;
					}

                    while( nTmp < nPos && CH_BLANK != rOldText.GetChar( 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 XubString aSnippet( rOldText, nOldPos, nTmp - nOldPos);
                        aNewText = CalcCaseMap( aSnippet );
                        aCapInf.nIdx = nOldPos;
                        aCapInf.nLen = nTmp - nOldPos;
                        rDo.GetInf().SetIdx( 0 );
                        rDo.GetInf().SetLen( aNewText.Len() );
                        rDo.GetInf().SetText( aNewText );
                    }
                    else
                    {
                        rDo.GetInf().SetIdx( nOldPos );
                        rDo.GetInf().SetLen( nTmp - nOldPos );
                    }

					rDo.GetInf().SetOut( *pOutSize );
					aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
					nKana += rDo.GetInf().GetKanaDiff();
					rDo.GetInf().SetOut( *pOldOut );
					if( !bWordWise && rDo.GetInf().GetSpace() )
                    {
                        for( xub_StrLen nI = nOldPos; nI < nPos; ++nI )
                        {
							if( CH_BLANK == rOldText.GetChar( nI ) )
                                aPartSize.Width() += nSpaceAdd;
                        }
                    }
                    if( nTmpKern && nPos < nMaxPos )
                        aPartSize.Width() += nTmpKern;
					rDo.Do();
					nOldPos = nTmp;
				}
			} while( nOldPos != nPos );
		}
		nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfCharBlock( rOldText, nPos,
			   pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
		if( nPos == STRING_LEN || nPos > nMaxPos )
			nPos = nMaxPos;
		ASSERT( nPos, "endOfCharBlock not implemented?" );
#ifdef DBG_UTIL
		if( !nPos )
			nPos = nMaxPos;
#endif
	}

	// Aufraeumen:
	if( pBigFont != pOldLast )
		delete pBigFontAccess;

	if( bTextLines )
	{
		if( rDo.GetInf().GetDrawSpace() )
		{
			pLastFont = pSpaceFont;
			pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
			( (SwDoDrawCapital&) rDo ).DrawSpace( aStartPos );
		}
		if ( bWordWise )
			delete pSpaceFontAccess;
	}
	pLastFont =	pOldLast;
	pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );

	delete pSmallFontAccess;
	rDo.GetInf().SetText( rOldText );
	rDo.GetInf().SetKanaDiff( nKana );
}

// JP 22.8.2001 - global optimization off - Bug 91245 / 91223
#ifdef _MSC_VER
#pragma optimize("g",on)
#endif


