/**************************************************************
 * 
 * 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_editeng.hxx"

// include ----------------------------------------------------------------

#include <vcl/outdev.hxx>
#include <vcl/print.hxx>
#include <tools/poly.hxx>
#include <unotools/charclass.hxx>
#include <editeng/unolingu.hxx>
#include <com/sun/star/i18n/KCharacterType.hpp>

#define _SVX_SVXFONT_CXX

#include <editeng/svxfont.hxx>
#include <editeng/escpitem.hxx>

// Minimum: Prozentwert fuers kernen
#define MINKERNPERCENT 5

// prop. Size of the small cap letters
#define KAPITAELCHENPROP 74

#ifndef REDUCEDSVXFONT
	const sal_Unicode CH_BLANK = sal_Unicode(' ');  	// ' ' Leerzeichen
	static sal_Char __READONLY_DATA sDoubleSpace[] = "  ";
#endif

/*************************************************************************
 *						class SvxFont
 *************************************************************************/

SvxFont::SvxFont()
{
	nKern = nEsc = 0;
	nPropr = 100;
	eCaseMap = SVX_CASEMAP_NOT_MAPPED;
	eLang = LANGUAGE_SYSTEM;
}

SvxFont::SvxFont( const Font &rFont )
	: Font( rFont )
{
	nKern = nEsc = 0;
	nPropr = 100;
	eCaseMap = SVX_CASEMAP_NOT_MAPPED;
	eLang = LANGUAGE_SYSTEM;
}

/*************************************************************************
 *						class SvxFont: Copy-Ctor
 *************************************************************************/

SvxFont::SvxFont( const SvxFont &rFont )
	: Font( rFont )
{
	nKern = rFont.GetFixKerning();
	nEsc  = rFont.GetEscapement();
	nPropr = rFont.GetPropr();
	eCaseMap = rFont.GetCaseMap();
	eLang = rFont.GetLanguage();
}

/*************************************************************************
 *				 static	SvxFont::DrawArrow
 *************************************************************************/

void SvxFont::DrawArrow( OutputDevice &rOut, const Rectangle& rRect,
	const Size& rSize, const Color& rCol, sal_Bool bLeft )
{
	long nLeft = ( rRect.Left() + rRect.Right() - rSize.Width() )/ 2;
	long nRight = nLeft + rSize.Width();
	long nMid = ( rRect.Top() + rRect.Bottom() ) / 2;
	long nTop = nMid - rSize.Height() / 2;
	long nBottom = nTop + rSize.Height();
	if( nLeft < rRect.Left() )
	{
		nLeft = rRect.Left();
		nRight = rRect.Right();
	}
	if( nTop < rRect.Top() )
	{
		nTop = rRect.Top();
		nBottom = rRect.Bottom();
	}
	Polygon aPoly;
	Point aTmp( bLeft ? nLeft : nRight, nMid );
	Point aNxt( bLeft ? nRight : nLeft, nTop );
	aPoly.Insert( 0, aTmp );
	aPoly.Insert( 0, aNxt );
	aNxt.Y() = nBottom;
	aPoly.Insert( 0, aNxt );
	aPoly.Insert( 0, aTmp );
	Color aOldLineColor = rOut.GetLineColor();
	Color aOldFillColor = rOut.GetFillColor();
	rOut.SetFillColor( rCol );
	rOut.SetLineColor( Color( COL_BLACK ) );
	rOut.DrawPolygon( aPoly );
	rOut.DrawLine( aTmp, aNxt );
	rOut.SetLineColor( aOldLineColor );
	rOut.SetFillColor( aOldFillColor );
}

/*************************************************************************
 *                      SvxFont::CalcCaseMap
 *************************************************************************/

XubString SvxFont::CalcCaseMap( const XubString &rTxt ) const
{
	if( !IsCaseMap() || !rTxt.Len() ) return rTxt;
	XubString aTxt( rTxt );
	// Ich muss mir noch die Sprache besorgen
	const LanguageType eLng = LANGUAGE_DONTKNOW == eLang
							? LANGUAGE_SYSTEM : eLang;

	CharClass aCharClass( SvxCreateLocale( eLng ) );

	switch( eCaseMap )
	{
		case SVX_CASEMAP_KAPITAELCHEN:
		case SVX_CASEMAP_VERSALIEN:
		{
			aCharClass.toUpper( aTxt );
			break;
		}

		case SVX_CASEMAP_GEMEINE:
		{
			aCharClass.toLower( aTxt );
			break;
		}
		case SVX_CASEMAP_TITEL:
		{
			// Jeder Wortbeginn wird gross geschrieben,
			// der Rest des Wortes wird unbesehen uebernommen.
			// Bug: wenn das Attribut mitten im Wort beginnt.
			sal_Bool bBlank = sal_True;

			for( sal_uInt16 i = 0; i < aTxt.Len(); ++i )
			{
				if( sal_Unicode(' ') == aTxt.GetChar(i) || sal_Unicode('\t') == aTxt.GetChar(i) )
					bBlank = sal_True;
				else
				{
					if( bBlank )
					{
						String aTemp( aTxt.GetChar( i ) );
						aCharClass.toUpper( aTemp );
						aTxt.Replace( i, 1, aTemp );
					}
					bBlank = sal_False;
				}
			}
			break;
		}
		default:
		{
			DBG_ASSERT(!this, "SvxFont::CaseMapTxt: unknown casemap");
			break;
		}
	}
	return aTxt;
}

/*************************************************************************
 * Hier beginnen die Methoden, die im Writer nicht benutzt werden koennen,
 * deshalb kann man diesen Bereich durch setzen von REDUCEDSVXFONT ausklammern.
 *************************************************************************/
#ifndef REDUCEDSVXFONT

/*************************************************************************
 *						class SvxDoCapitals
 * die virtuelle Methode Do wird von SvxFont::DoOnCapitals abwechselnd mit
 * den "Gross-" und "Kleinbuchstaben"-Teilen aufgerufen.
 * Die Ableitungen von SvxDoCapitals erfuellen diese Methode mit Leben.
 *************************************************************************/

class SvxDoCapitals
{
protected:
	OutputDevice *pOut;
	const XubString &rTxt;
	const xub_StrLen nIdx;
	const xub_StrLen nLen;

public:
    SvxDoCapitals( OutputDevice *_pOut, const XubString &_rTxt,
                   const xub_StrLen _nIdx, const xub_StrLen _nLen )
        : pOut(_pOut), rTxt(_rTxt), nIdx(_nIdx), nLen(_nLen)
		{ }

	virtual void DoSpace( const sal_Bool bDraw );
	virtual void SetSpace();
	virtual void Do( const XubString &rTxt,
					 const xub_StrLen nIdx, const xub_StrLen nLen,
					 const sal_Bool bUpper ) = 0;

	inline OutputDevice *GetOut() { return pOut; }
	inline const XubString &GetTxt() const { return rTxt; }
	xub_StrLen GetIdx() const { return nIdx; }
	xub_StrLen GetLen() const { return nLen; }
};

void SvxDoCapitals::DoSpace( const sal_Bool /*bDraw*/ ) { }

void SvxDoCapitals::SetSpace() { }

void SvxDoCapitals::Do( const XubString &/*_rTxt*/, const xub_StrLen /*_nIdx*/,
    const xub_StrLen /*_nLen*/, const sal_Bool /*bUpper*/ ) { }

/*************************************************************************
 *					SvxFont::DoOnCapitals() const
 * zerlegt den String in Gross- und Kleinbuchstaben und ruft jeweils die
 * Methode SvxDoCapitals::Do( ) auf.
 *************************************************************************/

void SvxFont::DoOnCapitals(SvxDoCapitals &rDo, const xub_StrLen nPartLen) const
{
	const XubString &rTxt = rDo.GetTxt();
	const xub_StrLen nIdx = rDo.GetIdx();
	const xub_StrLen nLen = STRING_LEN == nPartLen ? rDo.GetLen() : nPartLen;

	const XubString aTxt( CalcCaseMap( rTxt ) );
	const sal_uInt16 nTxtLen = Min( rTxt.Len(), nLen );
	sal_uInt16 nPos = 0;
	sal_uInt16 nOldPos = nPos;

	// #108210#
	// Test if string length differ between original and CaseMapped
	sal_Bool bCaseMapLengthDiffers(aTxt.Len() != rTxt.Len());

	const LanguageType eLng = LANGUAGE_DONTKNOW == eLang
							? LANGUAGE_SYSTEM : eLang;

	CharClass	aCharClass( SvxCreateLocale( eLng ) );
	String		aCharString;

	while( nPos < nTxtLen )
	{
		// Erst kommen die Upper-Chars dran

		// 4251: Es gibt Zeichen, die Upper _und_ Lower sind (z.B. das Blank).
		// Solche Zweideutigkeiten fuehren ins Chaos, deswegen werden diese
		// Zeichen der Menge Lower zugeordnet !

		while( nPos < nTxtLen )
		{
			aCharString = rTxt.GetChar( nPos + nIdx );
			sal_Int32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
			if ( nCharacterType & ::com::sun::star::i18n::KCharacterType::LOWER )
				break;
			if ( ! ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) )
				break;
			++nPos;
		}
		if( nOldPos != nPos )
		{
			if(bCaseMapLengthDiffers)
			{
				// #108210#
				// If strings differ work preparing the necessary snippet to address that
				// potential difference
				const XubString aSnippet(rTxt, nIdx + nOldPos, nPos-nOldPos);
				XubString aNewText = CalcCaseMap(aSnippet);
				
				rDo.Do( aNewText, 0, aNewText.Len(), sal_True );
			}
			else
			{
				rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, sal_True );
			}

			nOldPos = nPos;
		}
		// Nun werden die Lower-Chars verarbeitet (ohne Blanks)
		while( nPos < nTxtLen )
		{
			sal_uInt32	nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
			if ( ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) )
				break;
			if ( CH_BLANK == aCharString )
				break;
			if( ++nPos < nTxtLen )
				aCharString = rTxt.GetChar( nPos + nIdx );
		}
		if( nOldPos != nPos )
		{
			if(bCaseMapLengthDiffers)
			{
				// #108210#
				// If strings differ work preparing the necessary snippet to address that
				// potential difference
				const XubString aSnippet(rTxt, nIdx + nOldPos, nPos - nOldPos);
				XubString aNewText = CalcCaseMap(aSnippet);
				
				rDo.Do( aNewText, 0, aNewText.Len(), sal_False );
			}
			else
			{
				rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, sal_False );
			}

			nOldPos = nPos;
		}
		// Nun werden die Blanks verarbeitet
		while( nPos < nTxtLen && CH_BLANK == aCharString && ++nPos < nTxtLen )
			aCharString = rTxt.GetChar( nPos + nIdx );

		if( nOldPos != nPos )
		{
			rDo.DoSpace( sal_False );
			
			if(bCaseMapLengthDiffers)
			{
				// #108210#
				// If strings differ work preparing the necessary snippet to address that
				// potential difference
				const XubString aSnippet(rTxt, nIdx + nOldPos, nPos - nOldPos);
				XubString aNewText = CalcCaseMap(aSnippet);
				
				rDo.Do( aNewText, 0, aNewText.Len(), sal_False );
			}
			else
			{
				rDo.Do( aTxt, nIdx + nOldPos, nPos - nOldPos, sal_False );
			}

			nOldPos = nPos;
			rDo.SetSpace();
		}
	}
	rDo.DoSpace( sal_True );
}

/**************************************************************************
 *					  SvxFont::SetPhysFont()
 *************************************************************************/

void SvxFont::SetPhysFont( OutputDevice *pOut ) const
{
	const Font& rCurrentFont = pOut->GetFont();
	if ( nPropr == 100 )
	{
		if ( !rCurrentFont.IsSameInstance( *this ) )
			pOut->SetFont( *this );
	}
	else
	{
		Font aNewFont( *this );
		Size aSize( aNewFont.GetSize() );
		aNewFont.SetSize( Size(	aSize.Width() * nPropr / 100L,
									aSize.Height() * nPropr / 100L ) );
		if ( !rCurrentFont.IsSameInstance( aNewFont ) )
			pOut->SetFont( aNewFont );
	}
}

/*************************************************************************
 *					  SvxFont::ChgPhysFont()
 *************************************************************************/

Font SvxFont::ChgPhysFont( OutputDevice *pOut ) const
{
	Font aOldFont( pOut->GetFont() );
	SetPhysFont( pOut );
	return aOldFont;
}

/*************************************************************************
 *					  SvxFont::GetPhysTxtSize()
 *************************************************************************/

Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const XubString &rTxt,
						 const xub_StrLen nIdx, const xub_StrLen nLen ) const
{
	if ( !IsCaseMap() && !IsKern() )
		return Size( pOut->GetTextWidth( rTxt, nIdx, nLen ),
					 pOut->GetTextHeight() );

	Size aTxtSize;
	aTxtSize.setHeight( pOut->GetTextHeight() );
	if ( !IsCaseMap() )
		aTxtSize.setWidth( pOut->GetTextWidth( rTxt, nIdx, nLen ) );
	else
	{
		// #108210#
		const XubString aNewText = CalcCaseMap(rTxt);
		sal_Bool bCaseMapLengthDiffers(aNewText.Len() != rTxt.Len());
		sal_Int32 nWidth(0L);

		if(bCaseMapLengthDiffers)
		{
			// If strings differ work preparing the necessary snippet to address that
			// potential difference
			const XubString aSnippet(rTxt, nIdx, nLen);
            XubString _aNewText = CalcCaseMap(aSnippet);
            nWidth = pOut->GetTextWidth( _aNewText, 0, _aNewText.Len() );
		}
		else
		{
			nWidth = pOut->GetTextWidth( aNewText, nIdx, nLen );
		}

		aTxtSize.setWidth(nWidth);
	}

	if( IsKern() && ( nLen > 1 ) )
		aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) );

	return aTxtSize;
}

Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const XubString &rTxt )
{
	if ( !IsCaseMap() && !IsKern() )
		return Size( pOut->GetTextWidth( rTxt ), pOut->GetTextHeight() );

	Size aTxtSize;
	aTxtSize.setHeight( pOut->GetTextHeight() );
	if ( !IsCaseMap() )
		aTxtSize.setWidth( pOut->GetTextWidth( rTxt ) );
	else
		aTxtSize.setWidth( pOut->GetTextWidth( CalcCaseMap( rTxt ) ) );

	if( IsKern() && ( rTxt.Len() > 1 ) )
		aTxtSize.Width() += ( ( rTxt.Len()-1 ) * long( nKern ) );

	return aTxtSize;
}

Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const XubString &rTxt,
						 const sal_uInt16 nIdx, const sal_uInt16 nLen, sal_Int32* pDXArray ) const
{
	if ( !IsCaseMap() && !IsKern() )
		return Size( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ),
					 pOut->GetTextHeight() );

	Size aTxtSize;
	aTxtSize.setHeight( pOut->GetTextHeight() );
	if ( !IsCaseMap() )
		aTxtSize.setWidth( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ) );
	else
		aTxtSize.setWidth( pOut->GetTextArray( CalcCaseMap( rTxt ),
						   pDXArray, nIdx, nLen ) );

	if( IsKern() && ( nLen > 1 ) )
	{
		aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) );

		if ( pDXArray )
		{
			for ( xub_StrLen i = 0; i < nLen; i++ )
				pDXArray[i] += ( (i+1) * long( nKern ) );
			// Der letzte ist um ein nKern zu gross:
			pDXArray[nLen-1] -= nKern;
		}
	}
	return aTxtSize;
}

/*************************************************************************
 *					  SvxFont::GetTxtSize()
 *************************************************************************/

Size SvxFont::GetTxtSize( const OutputDevice *pOut, const XubString &rTxt,
						 const xub_StrLen nIdx, const xub_StrLen nLen )
{
	xub_StrLen nTmp = nLen;
	if ( nTmp == STRING_LEN )	// schon initialisiert?
		nTmp = rTxt.Len();
	Font aOldFont( ChgPhysFont((OutputDevice *)pOut) );
	Size aTxtSize;
	if( IsCapital() && rTxt.Len() )
	{
		aTxtSize = GetCapitalSize( pOut, rTxt, nIdx, nTmp );
	}
	else aTxtSize = GetPhysTxtSize(pOut,rTxt,nIdx,nTmp);
	((OutputDevice *)pOut)->SetFont( aOldFont );
	return aTxtSize;
}

/*************************************************************************
 *					  SvxFont::DrawText()
 *************************************************************************/

void SvxFont::DrawText( OutputDevice *pOut,
			   const Point &rPos, const XubString &rTxt,
			   const xub_StrLen nIdx, const xub_StrLen nLen ) const
{
	if( !nLen || !rTxt.Len() )	return;
	xub_StrLen nTmp = nLen;
	if ( nTmp == STRING_LEN )	// schon initialisiert?
		nTmp = rTxt.Len();
	Point aPos( rPos );
	if ( nEsc )
	{
		Size aSize = (this->GetSize());
		aPos.Y() -= ((nEsc*long(aSize.Height()))/ 100L);
	}
	Font aOldFont( ChgPhysFont( pOut ) );

	if ( IsCapital() )
		DrawCapital( pOut, aPos, rTxt, nIdx, nTmp );
	else
	{
		Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nTmp );

		if ( !IsCaseMap() )
			pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
		else
			pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ),
								   nIdx, nTmp );
	}
	pOut->SetFont(aOldFont);
}

void SvxFont::QuickDrawText( OutputDevice *pOut,
	const Point &rPos, const XubString &rTxt,
	const xub_StrLen nIdx, const xub_StrLen nLen, const sal_Int32* pDXArray ) const
{
	// Font muss ins OutputDevice selektiert sein...
	if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() )
	{
		pOut->DrawTextArray( rPos, rTxt, pDXArray, nIdx, nLen );
		return;
	}

	Point aPos( rPos );

    if ( nEsc )
    {
        long nDiff = GetSize().Height();
        nDiff *= nEsc;
        nDiff /= 100;

        if ( !IsVertical() )
		    aPos.Y() -= nDiff;
        else
            aPos.X() += nDiff;
    }

	if( IsCapital() )
	{
		DBG_ASSERT( !pDXArray, "DrawCapital nicht fuer TextArray!" );
		DrawCapital( pOut, aPos, rTxt, nIdx, nLen );
	}
	else
	{
		if ( IsKern() && !pDXArray )
		{
			Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen );

			if ( !IsCaseMap() )
				pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nLen );
			else
				pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nLen );
		}
		else
		{
			if ( !IsCaseMap() )
				pOut->DrawTextArray( aPos, rTxt, pDXArray, nIdx, nLen );
			else
				pOut->DrawTextArray( aPos, CalcCaseMap( rTxt ), pDXArray, nIdx, nLen );
		}
	}
}

// -----------------------------------------------------------------------

void SvxFont::DrawPrev( OutputDevice *pOut, Printer* pPrinter,
						const Point &rPos, const XubString &rTxt,
						const xub_StrLen nIdx, const xub_StrLen nLen ) const
{
	if ( !nLen || !rTxt.Len() )
		return;
	xub_StrLen nTmp = nLen;

	if ( nTmp == STRING_LEN )	// schon initialisiert?
		nTmp = rTxt.Len();
	Point aPos( rPos );

	if ( nEsc )
	{
		short nTmpEsc;
		if( DFLT_ESC_AUTO_SUPER == nEsc )
			nTmpEsc = 33;
		else if( DFLT_ESC_AUTO_SUB == nEsc )
			nTmpEsc = -20;
		else
			nTmpEsc = nEsc;
		Size aSize = ( this->GetSize() );
		aPos.Y() -= ( ( nTmpEsc * long( aSize.Height() ) ) / 100L );
	}
	Font aOldFont( ChgPhysFont( pOut ) );
	Font aOldPrnFont( ChgPhysFont( pPrinter ) );

	if ( IsCapital() )
		DrawCapital( pOut, aPos, rTxt, nIdx, nTmp );
	else
	{
		Size aSize = GetPhysTxtSize( pPrinter, rTxt, nIdx, nTmp );

		if ( !IsCaseMap() )
			pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
		else
		{
			// #108210#
			const XubString aNewText = CalcCaseMap(rTxt);
			sal_Bool bCaseMapLengthDiffers(aNewText.Len() != rTxt.Len());

			if(bCaseMapLengthDiffers)
			{
				// If strings differ work preparing the necessary snippet to address that
				// potential difference
				const XubString aSnippet(rTxt, nIdx, nTmp);
                XubString _aNewText = CalcCaseMap(aSnippet);

                pOut->DrawStretchText( aPos, aSize.Width(), _aNewText, 0, _aNewText.Len() );
			}
			else
			{
				pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nTmp );
			}
		}
	}
	pOut->SetFont(aOldFont);
	pPrinter->SetFont( aOldPrnFont );
}

// -----------------------------------------------------------------------

SvxFont& SvxFont::operator=( const Font& rFont )
{
	Font::operator=( rFont );
	return *this;
}

SvxFont& SvxFont::operator=( const SvxFont& rFont )
{
	Font::operator=( rFont );
	eLang = rFont.eLang;
	eCaseMap = rFont.eCaseMap;
	nEsc = rFont.nEsc;
	nPropr = rFont.nPropr;
	nKern = rFont.nKern;
	return *this;
}


/*************************************************************************
 *					  class SvxDoGetCapitalSize
 * wird von SvxFont::GetCapitalSize() zur Berechnung der TxtSize bei
 * eingestellten Kapitaelchen benutzt.
 *************************************************************************/

class SvxDoGetCapitalSize : public SvxDoCapitals
{
protected:
	SvxFont*	pFont;
	Size 		aTxtSize;
	short    	nKern;
public:
      SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut,
                           const XubString &_rTxt, const xub_StrLen _nIdx,
                           const xub_StrLen _nLen, const short _nKrn )
            : SvxDoCapitals( (OutputDevice*)_pOut, _rTxt, _nIdx, _nLen ),
              pFont( _pFnt ),
              nKern( _nKrn )
			{ }

	virtual void Do( const XubString &rTxt, const xub_StrLen nIdx,
					 const xub_StrLen nLen, const sal_Bool bUpper );

	inline const Size &GetSize() const { return aTxtSize; };
};

void SvxDoGetCapitalSize::Do( const XubString &_rTxt, const xub_StrLen _nIdx,
                              const xub_StrLen _nLen, const sal_Bool bUpper )
{
	Size aPartSize;
	if ( !bUpper )
	{
		sal_uInt8 nProp = pFont->GetPropr();
		pFont->SetProprRel( KAPITAELCHENPROP );
		pFont->SetPhysFont( pOut );
        aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
		aPartSize.setHeight( pOut->GetTextHeight() );
		aTxtSize.Height() = aPartSize.Height();
		pFont->SetPropr( nProp );
		pFont->SetPhysFont( pOut );
	}
	else
	{
        aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
		aPartSize.setHeight( pOut->GetTextHeight() );
	}
	aTxtSize.Width() += aPartSize.Width();
    aTxtSize.Width() += ( _nLen * long( nKern ) );
}

/*************************************************************************
 *					  SvxFont::GetCapitalSize()
 * berechnet TxtSize, wenn Kapitaelchen eingestellt sind.
 *************************************************************************/

Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const XubString &rTxt,
							 const xub_StrLen nIdx, const xub_StrLen nLen) const
{
	// Start:
	SvxDoGetCapitalSize aDo( (SvxFont *)this, pOut, rTxt, nIdx, nLen, nKern );
	DoOnCapitals( aDo );
	Size aTxtSize( aDo.GetSize() );

	// End:
	if( !aTxtSize.Height() )
	{
		aTxtSize.setWidth( 0 );
		aTxtSize.setHeight( pOut->GetTextHeight() );
	}
	return aTxtSize;
}

/*************************************************************************
 *					   class SvxDoDrawCapital
 * wird von SvxFont::DrawCapital zur Ausgabe von Kapitaelchen benutzt.
 *************************************************************************/

class SvxDoDrawCapital : public SvxDoCapitals
{
protected:
	SvxFont *pFont;
	Point aPos;
	Point aSpacePos;
	short nKern;
public:
    SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const XubString &_rTxt,
                      const xub_StrLen _nIdx, const xub_StrLen _nLen,
                      const Point &rPos, const short nKrn )
        : SvxDoCapitals( _pOut, _rTxt, _nIdx, _nLen ),
		  pFont( pFnt ),
		  aPos( rPos ),
		  aSpacePos( rPos ),
		  nKern( nKrn )
		{ }
	virtual void DoSpace( const sal_Bool bDraw );
	virtual void SetSpace();
	virtual void Do( const XubString &rTxt, const xub_StrLen nIdx,
					 const xub_StrLen nLen, const sal_Bool bUpper );
};

void SvxDoDrawCapital::DoSpace( const sal_Bool bDraw )
{
	if ( bDraw || pFont->IsWordLineMode() )
	{
		sal_uInt16 nDiff = (sal_uInt16)(aPos.X() - aSpacePos.X());
		if ( nDiff )
		{
			sal_Bool bWordWise = pFont->IsWordLineMode();
			sal_Bool bTrans = pFont->IsTransparent();
			pFont->SetWordLineMode( sal_False );
			pFont->SetTransparent( sal_True );
			pFont->SetPhysFont( pOut );
			pOut->DrawStretchText( aSpacePos, nDiff, XubString( sDoubleSpace,
							RTL_TEXTENCODING_MS_1252 ), 0, 2 );
			pFont->SetWordLineMode( bWordWise );
			pFont->SetTransparent( bTrans );
			pFont->SetPhysFont( pOut );
		}
	}
}

void SvxDoDrawCapital::SetSpace()
{
	if ( pFont->IsWordLineMode() )
		aSpacePos.X() = aPos.X();
}

void SvxDoDrawCapital::Do( const XubString &_rTxt, const xub_StrLen _nIdx,
                           const xub_StrLen _nLen, const sal_Bool bUpper)
{
	sal_uInt8 nProp = 0;
	Size aPartSize;

	// Einstellen der gewuenschten Fonts
	FontUnderline eUnder = pFont->GetUnderline();
	FontStrikeout eStrike = pFont->GetStrikeout();
	pFont->SetUnderline( UNDERLINE_NONE );
	pFont->SetStrikeout( STRIKEOUT_NONE );
	if ( !bUpper )
	{
		nProp = pFont->GetPropr();
		pFont->SetProprRel( KAPITAELCHENPROP );
	}
	pFont->SetPhysFont( pOut );

    aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
	aPartSize.setHeight( pOut->GetTextHeight() );
	long nWidth = aPartSize.Width();
	if ( nKern )
	{
		aPos.X() += (nKern/2);
        if ( _nLen ) nWidth += (_nLen*long(nKern));
	}
    pOut->DrawStretchText(aPos,nWidth-nKern,_rTxt,_nIdx,_nLen);

	// Font restaurieren
	pFont->SetUnderline( eUnder );
	pFont->SetStrikeout( eStrike );
	if ( !bUpper )
		pFont->SetPropr( nProp );
	pFont->SetPhysFont( pOut );

	aPos.X() += nWidth-(nKern/2);
}

/*************************************************************************
 * SvxFont::DrawCapital() gibt Kapitaelchen aus.
 *************************************************************************/

void SvxFont::DrawCapital( OutputDevice *pOut,
			   const Point &rPos, const XubString &rTxt,
			   const xub_StrLen nIdx, const xub_StrLen nLen ) const
{
	SvxDoDrawCapital aDo( (SvxFont *)this,pOut,rTxt,nIdx,nLen,rPos,nKern );
	DoOnCapitals( aDo );
}

#endif // !REDUCEDSVXFONT


