xref: /aoo42x/main/editeng/source/items/svxfont.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_editeng.hxx"
30 
31 // include ----------------------------------------------------------------
32 
33 #include <vcl/outdev.hxx>
34 #include <vcl/print.hxx>
35 #include <tools/poly.hxx>
36 #include <unotools/charclass.hxx>
37 #include <editeng/unolingu.hxx>
38 #include <com/sun/star/i18n/KCharacterType.hpp>
39 
40 #define _SVX_SVXFONT_CXX
41 
42 #include <editeng/svxfont.hxx>
43 #include <editeng/escpitem.hxx>
44 
45 // Minimum: Prozentwert fuers kernen
46 #define MINKERNPERCENT 5
47 
48 // prop. Groesse der Kleinbuchstaben bei Kapitaelchen
49 #define KAPITAELCHENPROP 66
50 
51 #ifndef REDUCEDSVXFONT
52 	const sal_Unicode CH_BLANK = sal_Unicode(' ');  	// ' ' Leerzeichen
53 	static sal_Char __READONLY_DATA sDoubleSpace[] = "  ";
54 #endif
55 
56 /*************************************************************************
57  *						class SvxFont
58  *************************************************************************/
59 
60 SvxFont::SvxFont()
61 {
62 	nKern = nEsc = 0;
63 	nPropr = 100;
64 	eCaseMap = SVX_CASEMAP_NOT_MAPPED;
65 	eLang = LANGUAGE_SYSTEM;
66 }
67 
68 SvxFont::SvxFont( const Font &rFont )
69 	: Font( rFont )
70 {
71 	nKern = nEsc = 0;
72 	nPropr = 100;
73 	eCaseMap = SVX_CASEMAP_NOT_MAPPED;
74 	eLang = LANGUAGE_SYSTEM;
75 }
76 
77 /*************************************************************************
78  *						class SvxFont: Copy-Ctor
79  *************************************************************************/
80 
81 SvxFont::SvxFont( const SvxFont &rFont )
82 	: Font( rFont )
83 {
84 	nKern = rFont.GetFixKerning();
85 	nEsc  = rFont.GetEscapement();
86 	nPropr = rFont.GetPropr();
87 	eCaseMap = rFont.GetCaseMap();
88 	eLang = rFont.GetLanguage();
89 }
90 
91 /*************************************************************************
92  *				 static	SvxFont::DrawArrow
93  *************************************************************************/
94 
95 void SvxFont::DrawArrow( OutputDevice &rOut, const Rectangle& rRect,
96 	const Size& rSize, const Color& rCol, sal_Bool bLeft )
97 {
98 	long nLeft = ( rRect.Left() + rRect.Right() - rSize.Width() )/ 2;
99 	long nRight = nLeft + rSize.Width();
100 	long nMid = ( rRect.Top() + rRect.Bottom() ) / 2;
101 	long nTop = nMid - rSize.Height() / 2;
102 	long nBottom = nTop + rSize.Height();
103 	if( nLeft < rRect.Left() )
104 	{
105 		nLeft = rRect.Left();
106 		nRight = rRect.Right();
107 	}
108 	if( nTop < rRect.Top() )
109 	{
110 		nTop = rRect.Top();
111 		nBottom = rRect.Bottom();
112 	}
113 	Polygon aPoly;
114 	Point aTmp( bLeft ? nLeft : nRight, nMid );
115 	Point aNxt( bLeft ? nRight : nLeft, nTop );
116 	aPoly.Insert( 0, aTmp );
117 	aPoly.Insert( 0, aNxt );
118 	aNxt.Y() = nBottom;
119 	aPoly.Insert( 0, aNxt );
120 	aPoly.Insert( 0, aTmp );
121 	Color aOldLineColor = rOut.GetLineColor();
122 	Color aOldFillColor = rOut.GetFillColor();
123 	rOut.SetFillColor( rCol );
124 	rOut.SetLineColor( Color( COL_BLACK ) );
125 	rOut.DrawPolygon( aPoly );
126 	rOut.DrawLine( aTmp, aNxt );
127 	rOut.SetLineColor( aOldLineColor );
128 	rOut.SetFillColor( aOldFillColor );
129 }
130 
131 /*************************************************************************
132  *                      SvxFont::CalcCaseMap
133  *************************************************************************/
134 
135 XubString SvxFont::CalcCaseMap( const XubString &rTxt ) const
136 {
137 	if( !IsCaseMap() || !rTxt.Len() ) return rTxt;
138 	XubString aTxt( rTxt );
139 	// Ich muss mir noch die Sprache besorgen
140 	const LanguageType eLng = LANGUAGE_DONTKNOW == eLang
141 							? LANGUAGE_SYSTEM : eLang;
142 
143 	CharClass aCharClass( SvxCreateLocale( eLng ) );
144 
145 	switch( eCaseMap )
146 	{
147 		case SVX_CASEMAP_KAPITAELCHEN:
148 		case SVX_CASEMAP_VERSALIEN:
149 		{
150 			aCharClass.toUpper( aTxt );
151 			break;
152 		}
153 
154 		case SVX_CASEMAP_GEMEINE:
155 		{
156 			aCharClass.toLower( aTxt );
157 			break;
158 		}
159 		case SVX_CASEMAP_TITEL:
160 		{
161 			// Jeder Wortbeginn wird gross geschrieben,
162 			// der Rest des Wortes wird unbesehen uebernommen.
163 			// Bug: wenn das Attribut mitten im Wort beginnt.
164 			sal_Bool bBlank = sal_True;
165 
166 			for( sal_uInt16 i = 0; i < aTxt.Len(); ++i )
167 			{
168 				if( sal_Unicode(' ') == aTxt.GetChar(i) || sal_Unicode('\t') == aTxt.GetChar(i) )
169 					bBlank = sal_True;
170 				else
171 				{
172 					if( bBlank )
173 					{
174 						String aTemp( aTxt.GetChar( i ) );
175 						aCharClass.toUpper( aTemp );
176 						aTxt.Replace( i, 1, aTemp );
177 					}
178 					bBlank = sal_False;
179 				}
180 			}
181 			break;
182 		}
183 		default:
184 		{
185 			DBG_ASSERT(!this, "SvxFont::CaseMapTxt: unknown casemap");
186 			break;
187 		}
188 	}
189 	return aTxt;
190 }
191 
192 /*************************************************************************
193  * Hier beginnen die Methoden, die im Writer nicht benutzt werden koennen,
194  * deshalb kann man diesen Bereich durch setzen von REDUCEDSVXFONT ausklammern.
195  *************************************************************************/
196 #ifndef REDUCEDSVXFONT
197 
198 /*************************************************************************
199  *						class SvxDoCapitals
200  * die virtuelle Methode Do wird von SvxFont::DoOnCapitals abwechselnd mit
201  * den "Gross-" und "Kleinbuchstaben"-Teilen aufgerufen.
202  * Die Ableitungen von SvxDoCapitals erfuellen diese Methode mit Leben.
203  *************************************************************************/
204 
205 class SvxDoCapitals
206 {
207 protected:
208 	OutputDevice *pOut;
209 	const XubString &rTxt;
210 	const xub_StrLen nIdx;
211 	const xub_StrLen nLen;
212 
213 public:
214     SvxDoCapitals( OutputDevice *_pOut, const XubString &_rTxt,
215                    const xub_StrLen _nIdx, const xub_StrLen _nLen )
216         : pOut(_pOut), rTxt(_rTxt), nIdx(_nIdx), nLen(_nLen)
217 		{ }
218 
219 	virtual void DoSpace( const sal_Bool bDraw );
220 	virtual void SetSpace();
221 	virtual void Do( const XubString &rTxt,
222 					 const xub_StrLen nIdx, const xub_StrLen nLen,
223 					 const sal_Bool bUpper ) = 0;
224 
225 	inline OutputDevice *GetOut() { return pOut; }
226 	inline const XubString &GetTxt() const { return rTxt; }
227 	xub_StrLen GetIdx() const { return nIdx; }
228 	xub_StrLen GetLen() const { return nLen; }
229 };
230 
231 void SvxDoCapitals::DoSpace( const sal_Bool /*bDraw*/ ) { }
232 
233 void SvxDoCapitals::SetSpace() { }
234 
235 void SvxDoCapitals::Do( const XubString &/*_rTxt*/, const xub_StrLen /*_nIdx*/,
236     const xub_StrLen /*_nLen*/, const sal_Bool /*bUpper*/ ) { }
237 
238 /*************************************************************************
239  *					SvxFont::DoOnCapitals() const
240  * zerlegt den String in Gross- und Kleinbuchstaben und ruft jeweils die
241  * Methode SvxDoCapitals::Do( ) auf.
242  *************************************************************************/
243 
244 void SvxFont::DoOnCapitals(SvxDoCapitals &rDo, const xub_StrLen nPartLen) const
245 {
246 	const XubString &rTxt = rDo.GetTxt();
247 	const xub_StrLen nIdx = rDo.GetIdx();
248 	const xub_StrLen nLen = STRING_LEN == nPartLen ? rDo.GetLen() : nPartLen;
249 
250 	const XubString aTxt( CalcCaseMap( rTxt ) );
251 	const sal_uInt16 nTxtLen = Min( rTxt.Len(), nLen );
252 	sal_uInt16 nPos = 0;
253 	sal_uInt16 nOldPos = nPos;
254 
255 	// #108210#
256 	// Test if string length differ between original and CaseMapped
257 	sal_Bool bCaseMapLengthDiffers(aTxt.Len() != rTxt.Len());
258 
259 	const LanguageType eLng = LANGUAGE_DONTKNOW == eLang
260 							? LANGUAGE_SYSTEM : eLang;
261 
262 	CharClass	aCharClass( SvxCreateLocale( eLng ) );
263 	String		aCharString;
264 
265 	while( nPos < nTxtLen )
266 	{
267 		// Erst kommen die Upper-Chars dran
268 
269 		// 4251: Es gibt Zeichen, die Upper _und_ Lower sind (z.B. das Blank).
270 		// Solche Zweideutigkeiten fuehren ins Chaos, deswegen werden diese
271 		// Zeichen der Menge Lower zugeordnet !
272 
273 		while( nPos < nTxtLen )
274 		{
275 			aCharString = rTxt.GetChar( nPos + nIdx );
276 			sal_Int32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
277 			if ( nCharacterType & ::com::sun::star::i18n::KCharacterType::LOWER )
278 				break;
279 			if ( ! ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) )
280 				break;
281 			++nPos;
282 		}
283 		if( nOldPos != nPos )
284 		{
285 			if(bCaseMapLengthDiffers)
286 			{
287 				// #108210#
288 				// If strings differ work preparing the necessary snippet to address that
289 				// potential difference
290 				const XubString aSnippet(rTxt, nIdx + nOldPos, nPos-nOldPos);
291 				XubString aNewText = CalcCaseMap(aSnippet);
292 
293 				rDo.Do( aNewText, 0, aNewText.Len(), sal_True );
294 			}
295 			else
296 			{
297 				rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, sal_True );
298 			}
299 
300 			nOldPos = nPos;
301 		}
302 		// Nun werden die Lower-Chars verarbeitet (ohne Blanks)
303 		while( nPos < nTxtLen )
304 		{
305 			sal_uInt32	nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
306 			if ( ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) )
307 				break;
308 			if ( CH_BLANK == aCharString )
309 				break;
310 			if( ++nPos < nTxtLen )
311 				aCharString = rTxt.GetChar( nPos + nIdx );
312 		}
313 		if( nOldPos != nPos )
314 		{
315 			if(bCaseMapLengthDiffers)
316 			{
317 				// #108210#
318 				// If strings differ work preparing the necessary snippet to address that
319 				// potential difference
320 				const XubString aSnippet(rTxt, nIdx + nOldPos, nPos - nOldPos);
321 				XubString aNewText = CalcCaseMap(aSnippet);
322 
323 				rDo.Do( aNewText, 0, aNewText.Len(), sal_False );
324 			}
325 			else
326 			{
327 				rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, sal_False );
328 			}
329 
330 			nOldPos = nPos;
331 		}
332 		// Nun werden die Blanks verarbeitet
333 		while( nPos < nTxtLen && CH_BLANK == aCharString && ++nPos < nTxtLen )
334 			aCharString = rTxt.GetChar( nPos + nIdx );
335 
336 		if( nOldPos != nPos )
337 		{
338 			rDo.DoSpace( sal_False );
339 
340 			if(bCaseMapLengthDiffers)
341 			{
342 				// #108210#
343 				// If strings differ work preparing the necessary snippet to address that
344 				// potential difference
345 				const XubString aSnippet(rTxt, nIdx + nOldPos, nPos - nOldPos);
346 				XubString aNewText = CalcCaseMap(aSnippet);
347 
348 				rDo.Do( aNewText, 0, aNewText.Len(), sal_False );
349 			}
350 			else
351 			{
352 				rDo.Do( aTxt, nIdx + nOldPos, nPos - nOldPos, sal_False );
353 			}
354 
355 			nOldPos = nPos;
356 			rDo.SetSpace();
357 		}
358 	}
359 	rDo.DoSpace( sal_True );
360 }
361 
362 /**************************************************************************
363  *					  SvxFont::SetPhysFont()
364  *************************************************************************/
365 
366 void SvxFont::SetPhysFont( OutputDevice *pOut ) const
367 {
368 	const Font& rCurrentFont = pOut->GetFont();
369 	if ( nPropr == 100 )
370 	{
371 		if ( !rCurrentFont.IsSameInstance( *this ) )
372 			pOut->SetFont( *this );
373 	}
374 	else
375 	{
376 		Font aNewFont( *this );
377 		Size aSize( aNewFont.GetSize() );
378 		aNewFont.SetSize( Size(	aSize.Width() * nPropr / 100L,
379 									aSize.Height() * nPropr / 100L ) );
380 		if ( !rCurrentFont.IsSameInstance( aNewFont ) )
381 			pOut->SetFont( aNewFont );
382 	}
383 }
384 
385 /*************************************************************************
386  *					  SvxFont::ChgPhysFont()
387  *************************************************************************/
388 
389 Font SvxFont::ChgPhysFont( OutputDevice *pOut ) const
390 {
391 	Font aOldFont( pOut->GetFont() );
392 	SetPhysFont( pOut );
393 	return aOldFont;
394 }
395 
396 /*************************************************************************
397  *					  SvxFont::GetPhysTxtSize()
398  *************************************************************************/
399 
400 Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const XubString &rTxt,
401 						 const xub_StrLen nIdx, const xub_StrLen nLen ) const
402 {
403 	if ( !IsCaseMap() && !IsKern() )
404 		return Size( pOut->GetTextWidth( rTxt, nIdx, nLen ),
405 					 pOut->GetTextHeight() );
406 
407 	Size aTxtSize;
408 	aTxtSize.setHeight( pOut->GetTextHeight() );
409 	if ( !IsCaseMap() )
410 		aTxtSize.setWidth( pOut->GetTextWidth( rTxt, nIdx, nLen ) );
411 	else
412 	{
413 		// #108210#
414 		const XubString aNewText = CalcCaseMap(rTxt);
415 		sal_Bool bCaseMapLengthDiffers(aNewText.Len() != rTxt.Len());
416 		sal_Int32 nWidth(0L);
417 
418 		if(bCaseMapLengthDiffers)
419 		{
420 			// If strings differ work preparing the necessary snippet to address that
421 			// potential difference
422 			const XubString aSnippet(rTxt, nIdx, nLen);
423             XubString _aNewText = CalcCaseMap(aSnippet);
424             nWidth = pOut->GetTextWidth( _aNewText, 0, _aNewText.Len() );
425 		}
426 		else
427 		{
428 			nWidth = pOut->GetTextWidth( aNewText, nIdx, nLen );
429 		}
430 
431 		aTxtSize.setWidth(nWidth);
432 	}
433 
434 	if( IsKern() && ( nLen > 1 ) )
435 		aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) );
436 
437 	return aTxtSize;
438 }
439 
440 Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const XubString &rTxt )
441 {
442 	if ( !IsCaseMap() && !IsKern() )
443 		return Size( pOut->GetTextWidth( rTxt ), pOut->GetTextHeight() );
444 
445 	Size aTxtSize;
446 	aTxtSize.setHeight( pOut->GetTextHeight() );
447 	if ( !IsCaseMap() )
448 		aTxtSize.setWidth( pOut->GetTextWidth( rTxt ) );
449 	else
450 		aTxtSize.setWidth( pOut->GetTextWidth( CalcCaseMap( rTxt ) ) );
451 
452 	if( IsKern() && ( rTxt.Len() > 1 ) )
453 		aTxtSize.Width() += ( ( rTxt.Len()-1 ) * long( nKern ) );
454 
455 	return aTxtSize;
456 }
457 
458 Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const XubString &rTxt,
459 						 const sal_uInt16 nIdx, const sal_uInt16 nLen, sal_Int32* pDXArray ) const
460 {
461 	if ( !IsCaseMap() && !IsKern() )
462 		return Size( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ),
463 					 pOut->GetTextHeight() );
464 
465 	Size aTxtSize;
466 	aTxtSize.setHeight( pOut->GetTextHeight() );
467 	if ( !IsCaseMap() )
468 		aTxtSize.setWidth( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ) );
469 	else
470 		aTxtSize.setWidth( pOut->GetTextArray( CalcCaseMap( rTxt ),
471 						   pDXArray, nIdx, nLen ) );
472 
473 	if( IsKern() && ( nLen > 1 ) )
474 	{
475 		aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) );
476 
477 		if ( pDXArray )
478 		{
479 			for ( xub_StrLen i = 0; i < nLen; i++ )
480 				pDXArray[i] += ( (i+1) * long( nKern ) );
481 			// Der letzte ist um ein nKern zu gross:
482 			pDXArray[nLen-1] -= nKern;
483 		}
484 	}
485 	return aTxtSize;
486 }
487 
488 /*************************************************************************
489  *					  SvxFont::GetTxtSize()
490  *************************************************************************/
491 
492 Size SvxFont::GetTxtSize( const OutputDevice *pOut, const XubString &rTxt,
493 						 const xub_StrLen nIdx, const xub_StrLen nLen )
494 {
495 	xub_StrLen nTmp = nLen;
496 	if ( nTmp == STRING_LEN )	// schon initialisiert?
497 		nTmp = rTxt.Len();
498 	Font aOldFont( ChgPhysFont((OutputDevice *)pOut) );
499 	Size aTxtSize;
500 	if( IsCapital() && rTxt.Len() )
501 	{
502 		aTxtSize = GetCapitalSize( pOut, rTxt, nIdx, nTmp );
503 	}
504 	else aTxtSize = GetPhysTxtSize(pOut,rTxt,nIdx,nTmp);
505 	((OutputDevice *)pOut)->SetFont( aOldFont );
506 	return aTxtSize;
507 }
508 
509 /*************************************************************************
510  *					  SvxFont::DrawText()
511  *************************************************************************/
512 
513 void SvxFont::DrawText( OutputDevice *pOut,
514 			   const Point &rPos, const XubString &rTxt,
515 			   const xub_StrLen nIdx, const xub_StrLen nLen ) const
516 {
517 	if( !nLen || !rTxt.Len() )	return;
518 	xub_StrLen nTmp = nLen;
519 	if ( nTmp == STRING_LEN )	// schon initialisiert?
520 		nTmp = rTxt.Len();
521 	Point aPos( rPos );
522 	if ( nEsc )
523 	{
524 		Size aSize = (this->GetSize());
525 		aPos.Y() -= ((nEsc*long(aSize.Height()))/ 100L);
526 	}
527 	Font aOldFont( ChgPhysFont( pOut ) );
528 
529 	if ( IsCapital() )
530 		DrawCapital( pOut, aPos, rTxt, nIdx, nTmp );
531 	else
532 	{
533 		Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nTmp );
534 
535 		if ( !IsCaseMap() )
536 			pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
537 		else
538 			pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ),
539 								   nIdx, nTmp );
540 	}
541 	pOut->SetFont(aOldFont);
542 }
543 
544 void SvxFont::QuickDrawText( OutputDevice *pOut,
545 	const Point &rPos, const XubString &rTxt,
546 	const xub_StrLen nIdx, const xub_StrLen nLen, const sal_Int32* pDXArray ) const
547 {
548 	// Font muss ins OutputDevice selektiert sein...
549 	if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() )
550 	{
551 		pOut->DrawTextArray( rPos, rTxt, pDXArray, nIdx, nLen );
552 		return;
553 	}
554 
555 	Point aPos( rPos );
556 
557     if ( nEsc )
558     {
559         long nDiff = GetSize().Height();
560         nDiff *= nEsc;
561         nDiff /= 100;
562 
563         if ( !IsVertical() )
564 		    aPos.Y() -= nDiff;
565         else
566             aPos.X() += nDiff;
567     }
568 
569 	if( IsCapital() )
570 	{
571 		DBG_ASSERT( !pDXArray, "DrawCapital nicht fuer TextArray!" );
572 		DrawCapital( pOut, aPos, rTxt, nIdx, nLen );
573 	}
574 	else
575 	{
576 		if ( IsKern() && !pDXArray )
577 		{
578 			Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen );
579 
580 			if ( !IsCaseMap() )
581 				pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nLen );
582 			else
583 				pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nLen );
584 		}
585 		else
586 		{
587 			if ( !IsCaseMap() )
588 				pOut->DrawTextArray( aPos, rTxt, pDXArray, nIdx, nLen );
589 			else
590 				pOut->DrawTextArray( aPos, CalcCaseMap( rTxt ), pDXArray, nIdx, nLen );
591 		}
592 	}
593 }
594 
595 // -----------------------------------------------------------------------
596 
597 void SvxFont::DrawPrev( OutputDevice *pOut, Printer* pPrinter,
598 						const Point &rPos, const XubString &rTxt,
599 						const xub_StrLen nIdx, const xub_StrLen nLen ) const
600 {
601 	if ( !nLen || !rTxt.Len() )
602 		return;
603 	xub_StrLen nTmp = nLen;
604 
605 	if ( nTmp == STRING_LEN )	// schon initialisiert?
606 		nTmp = rTxt.Len();
607 	Point aPos( rPos );
608 
609 	if ( nEsc )
610 	{
611 		short nTmpEsc;
612 		if( DFLT_ESC_AUTO_SUPER == nEsc )
613 			nTmpEsc = 33;
614 		else if( DFLT_ESC_AUTO_SUB == nEsc )
615 			nTmpEsc = -20;
616 		else
617 			nTmpEsc = nEsc;
618 		Size aSize = ( this->GetSize() );
619 		aPos.Y() -= ( ( nTmpEsc * long( aSize.Height() ) ) / 100L );
620 	}
621 	Font aOldFont( ChgPhysFont( pOut ) );
622 	Font aOldPrnFont( ChgPhysFont( pPrinter ) );
623 
624 	if ( IsCapital() )
625 		DrawCapital( pOut, aPos, rTxt, nIdx, nTmp );
626 	else
627 	{
628 		Size aSize = GetPhysTxtSize( pPrinter, rTxt, nIdx, nTmp );
629 
630 		if ( !IsCaseMap() )
631 			pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
632 		else
633 		{
634 			// #108210#
635 			const XubString aNewText = CalcCaseMap(rTxt);
636 			sal_Bool bCaseMapLengthDiffers(aNewText.Len() != rTxt.Len());
637 
638 			if(bCaseMapLengthDiffers)
639 			{
640 				// If strings differ work preparing the necessary snippet to address that
641 				// potential difference
642 				const XubString aSnippet(rTxt, nIdx, nTmp);
643                 XubString _aNewText = CalcCaseMap(aSnippet);
644 
645                 pOut->DrawStretchText( aPos, aSize.Width(), _aNewText, 0, _aNewText.Len() );
646 			}
647 			else
648 			{
649 				pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nTmp );
650 			}
651 		}
652 	}
653 	pOut->SetFont(aOldFont);
654 	pPrinter->SetFont( aOldPrnFont );
655 }
656 
657 // -----------------------------------------------------------------------
658 
659 SvxFont& SvxFont::operator=( const Font& rFont )
660 {
661 	Font::operator=( rFont );
662 	return *this;
663 }
664 
665 SvxFont& SvxFont::operator=( const SvxFont& rFont )
666 {
667 	Font::operator=( rFont );
668 	eLang = rFont.eLang;
669 	eCaseMap = rFont.eCaseMap;
670 	nEsc = rFont.nEsc;
671 	nPropr = rFont.nPropr;
672 	nKern = rFont.nKern;
673 	return *this;
674 }
675 
676 
677 /*************************************************************************
678  *					  class SvxDoGetCapitalSize
679  * wird von SvxFont::GetCapitalSize() zur Berechnung der TxtSize bei
680  * eingestellten Kapitaelchen benutzt.
681  *************************************************************************/
682 
683 class SvxDoGetCapitalSize : public SvxDoCapitals
684 {
685 protected:
686 	SvxFont*	pFont;
687 	Size 		aTxtSize;
688 	short    	nKern;
689 public:
690       SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut,
691                            const XubString &_rTxt, const xub_StrLen _nIdx,
692                            const xub_StrLen _nLen, const short _nKrn )
693             : SvxDoCapitals( (OutputDevice*)_pOut, _rTxt, _nIdx, _nLen ),
694               pFont( _pFnt ),
695               nKern( _nKrn )
696 			{ }
697 
698 	virtual void Do( const XubString &rTxt, const xub_StrLen nIdx,
699 					 const xub_StrLen nLen, const sal_Bool bUpper );
700 
701 	inline const Size &GetSize() const { return aTxtSize; };
702 };
703 
704 void SvxDoGetCapitalSize::Do( const XubString &_rTxt, const xub_StrLen _nIdx,
705                               const xub_StrLen _nLen, const sal_Bool bUpper )
706 {
707 	Size aPartSize;
708 	if ( !bUpper )
709 	{
710 		sal_uInt8 nProp = pFont->GetPropr();
711 		pFont->SetProprRel( KAPITAELCHENPROP );
712 		pFont->SetPhysFont( pOut );
713         aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
714 		aPartSize.setHeight( pOut->GetTextHeight() );
715 		aTxtSize.Height() = aPartSize.Height();
716 		pFont->SetPropr( nProp );
717 		pFont->SetPhysFont( pOut );
718 	}
719 	else
720 	{
721         aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
722 		aPartSize.setHeight( pOut->GetTextHeight() );
723 	}
724 	aTxtSize.Width() += aPartSize.Width();
725     aTxtSize.Width() += ( _nLen * long( nKern ) );
726 }
727 
728 /*************************************************************************
729  *					  SvxFont::GetCapitalSize()
730  * berechnet TxtSize, wenn Kapitaelchen eingestellt sind.
731  *************************************************************************/
732 
733 Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const XubString &rTxt,
734 							 const xub_StrLen nIdx, const xub_StrLen nLen) const
735 {
736 	// Start:
737 	SvxDoGetCapitalSize aDo( (SvxFont *)this, pOut, rTxt, nIdx, nLen, nKern );
738 	DoOnCapitals( aDo );
739 	Size aTxtSize( aDo.GetSize() );
740 
741 	// End:
742 	if( !aTxtSize.Height() )
743 	{
744 		aTxtSize.setWidth( 0 );
745 		aTxtSize.setHeight( pOut->GetTextHeight() );
746 	}
747 	return aTxtSize;
748 }
749 
750 /*************************************************************************
751  *					   class SvxDoDrawCapital
752  * wird von SvxFont::DrawCapital zur Ausgabe von Kapitaelchen benutzt.
753  *************************************************************************/
754 
755 class SvxDoDrawCapital : public SvxDoCapitals
756 {
757 protected:
758 	SvxFont *pFont;
759 	Point aPos;
760 	Point aSpacePos;
761 	short nKern;
762 public:
763     SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const XubString &_rTxt,
764                       const xub_StrLen _nIdx, const xub_StrLen _nLen,
765                       const Point &rPos, const short nKrn )
766         : SvxDoCapitals( _pOut, _rTxt, _nIdx, _nLen ),
767 		  pFont( pFnt ),
768 		  aPos( rPos ),
769 		  aSpacePos( rPos ),
770 		  nKern( nKrn )
771 		{ }
772 	virtual void DoSpace( const sal_Bool bDraw );
773 	virtual void SetSpace();
774 	virtual void Do( const XubString &rTxt, const xub_StrLen nIdx,
775 					 const xub_StrLen nLen, const sal_Bool bUpper );
776 };
777 
778 void SvxDoDrawCapital::DoSpace( const sal_Bool bDraw )
779 {
780 	if ( bDraw || pFont->IsWordLineMode() )
781 	{
782 		sal_uInt16 nDiff = (sal_uInt16)(aPos.X() - aSpacePos.X());
783 		if ( nDiff )
784 		{
785 			sal_Bool bWordWise = pFont->IsWordLineMode();
786 			sal_Bool bTrans = pFont->IsTransparent();
787 			pFont->SetWordLineMode( sal_False );
788 			pFont->SetTransparent( sal_True );
789 			pFont->SetPhysFont( pOut );
790 			pOut->DrawStretchText( aSpacePos, nDiff, XubString( sDoubleSpace,
791 							RTL_TEXTENCODING_MS_1252 ), 0, 2 );
792 			pFont->SetWordLineMode( bWordWise );
793 			pFont->SetTransparent( bTrans );
794 			pFont->SetPhysFont( pOut );
795 		}
796 	}
797 }
798 
799 void SvxDoDrawCapital::SetSpace()
800 {
801 	if ( pFont->IsWordLineMode() )
802 		aSpacePos.X() = aPos.X();
803 }
804 
805 void SvxDoDrawCapital::Do( const XubString &_rTxt, const xub_StrLen _nIdx,
806                            const xub_StrLen _nLen, const sal_Bool bUpper)
807 {
808 	sal_uInt8 nProp = 0;
809 	Size aPartSize;
810 
811 	// Einstellen der gewuenschten Fonts
812 	FontUnderline eUnder = pFont->GetUnderline();
813 	FontStrikeout eStrike = pFont->GetStrikeout();
814 	pFont->SetUnderline( UNDERLINE_NONE );
815 	pFont->SetStrikeout( STRIKEOUT_NONE );
816 	if ( !bUpper )
817 	{
818 		nProp = pFont->GetPropr();
819 		pFont->SetProprRel( KAPITAELCHENPROP );
820 	}
821 	pFont->SetPhysFont( pOut );
822 
823     aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
824 	aPartSize.setHeight( pOut->GetTextHeight() );
825 	long nWidth = aPartSize.Width();
826 	if ( nKern )
827 	{
828 		aPos.X() += (nKern/2);
829         if ( _nLen ) nWidth += (_nLen*long(nKern));
830 	}
831     pOut->DrawStretchText(aPos,nWidth-nKern,_rTxt,_nIdx,_nLen);
832 
833 	// Font restaurieren
834 	pFont->SetUnderline( eUnder );
835 	pFont->SetStrikeout( eStrike );
836 	if ( !bUpper )
837 		pFont->SetPropr( nProp );
838 	pFont->SetPhysFont( pOut );
839 
840 	aPos.X() += nWidth-(nKern/2);
841 }
842 
843 /*************************************************************************
844  * SvxFont::DrawCapital() gibt Kapitaelchen aus.
845  *************************************************************************/
846 
847 void SvxFont::DrawCapital( OutputDevice *pOut,
848 			   const Point &rPos, const XubString &rTxt,
849 			   const xub_StrLen nIdx, const xub_StrLen nLen ) const
850 {
851 	SvxDoDrawCapital aDo( (SvxFont *)this,pOut,rTxt,nIdx,nLen,rPos,nKern );
852 	DoOnCapitals( aDo );
853 }
854 
855 #endif // !REDUCEDSVXFONT
856 
857 
858