xref: /trunk/main/sw/source/core/txtnode/fntcap.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <editeng/cmapitem.hxx>
30 
31 #ifndef _OUTDEV_HXX //autogen
32 #include <vcl/outdev.hxx>
33 #endif
34 #ifndef _COM_SUN_STAR_I18N_CHARTYPE_HDL
35 #include <com/sun/star/i18n/CharType.hdl>
36 #endif
37 #ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
38 #include <com/sun/star/i18n/WordType.hdl>
39 #endif
40 
41 #ifndef _PRINT_HXX //autogen
42 #include <vcl/print.hxx>
43 #endif
44 #include <errhdl.hxx>
45 #include <fntcache.hxx>
46 #include <swfont.hxx>
47 #include <breakit.hxx>
48 #include <txtfrm.hxx>       // SwTxtFrm
49 #include <scriptinfo.hxx>
50 
51 using namespace ::com::sun::star::i18n;
52 
53 
54 #define KAPITAELCHENPROP 74
55 
56 /*************************************************************************
57  *						class SwCapitalInfo
58  *
59  * The information encapsulated in SwCapitalInfo is required
60  * by the ::Do functions. They contain the information about
61  * the original string, whereas rDo.GetInf() contains information
62  * about the display string.
63  *************************************************************************/
64 
65 class SwCapitalInfo
66 {
67 public:
SwCapitalInfo(const XubString & rOrigText)68     explicit SwCapitalInfo( const XubString& rOrigText ) :
69         rString( rOrigText ), nIdx( 0 ), nLen( 0 ) {};
70     const XubString& rString;
71     xub_StrLen nIdx;
72     xub_StrLen nLen;
73 };
74 
75 /*************************************************************************
76  *						xub_StrLen lcl_CalcCaseMap()
77  *
78  * rFnt: required for CalcCaseMap
79  * rOrigString: The original string
80  * nOfst: Position of the substring in rOrigString
81  * nLen: Length if the substring in rOrigString
82  * nIdx: Referes to a position in the display string and should be mapped
83  *       to a position in rOrigString
84  *************************************************************************/
85 
lcl_CalcCaseMap(const SwFont & rFnt,const XubString & rOrigString,xub_StrLen nOfst,xub_StrLen nLen,xub_StrLen nIdx)86 xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt,
87                             const XubString& rOrigString,
88                             xub_StrLen nOfst,
89                             xub_StrLen nLen,
90                             xub_StrLen nIdx )
91 {
92     int j = 0;
93     const xub_StrLen nEnd = nOfst + nLen;
94     ASSERT( nEnd <= rOrigString.Len(), "lcl_CalcCaseMap: Wrong parameters" )
95 
96     // special case for title case:
97     const bool bTitle = SVX_CASEMAP_TITEL == rFnt.GetCaseMap() &&
98                         pBreakIt->GetBreakIter().is();
99     for ( xub_StrLen i = nOfst; i < nEnd; ++i )
100     {
101         XubString aTmp( rOrigString, i, 1 );
102 
103         if ( !bTitle ||
104              pBreakIt->GetBreakIter()->isBeginWord(
105                  rOrigString, i,
106                  pBreakIt->GetLocale( rFnt.GetLanguage() ),
107                  WordType::ANYWORD_IGNOREWHITESPACES ) )
108             aTmp = rFnt.GetActualFont().CalcCaseMap( aTmp );
109 
110         j += aTmp.Len();
111 
112         if ( j > nIdx )
113             return i;
114     }
115 
116     return nOfst + nLen;
117 }
118 
119 /*************************************************************************
120  *						class SwDoCapitals
121  *************************************************************************/
122 
123 class SwDoCapitals
124 {
125 protected:
126 	SwDrawTextInfo &rInf;
127     SwCapitalInfo* pCapInf; // referes to additional information
128                            // required by the ::Do function
129 public:
SwDoCapitals(SwDrawTextInfo & rInfo)130     SwDoCapitals ( SwDrawTextInfo &rInfo ) : rInf( rInfo ), pCapInf( 0 ) { }
131 	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) = 0;
132 	virtual void Do() = 0;
GetOut()133     inline OutputDevice& GetOut() { return rInf.GetOut(); }
GetInf()134 	inline SwDrawTextInfo& GetInf() { return rInf; }
GetCapInf() const135     inline SwCapitalInfo* GetCapInf() const { return pCapInf; }
SetCapInf(SwCapitalInfo & rNew)136     inline void SetCapInf( SwCapitalInfo& rNew ) { pCapInf = &rNew; }
137 };
138 
139 /*************************************************************************
140  *					  class SwDoGetCapitalSize
141  *************************************************************************/
142 
143 class SwDoGetCapitalSize : public SwDoCapitals
144 {
145 protected:
146 	Size aTxtSize;
147 public:
SwDoGetCapitalSize(SwDrawTextInfo & rInfo)148 	SwDoGetCapitalSize( SwDrawTextInfo &rInfo ) : SwDoCapitals ( rInfo ) { }
149 	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
150 	virtual void Do();
GetSize() const151 	const Size &GetSize() const { return aTxtSize; }
152 };
153 
Init(SwFntObj *,SwFntObj *)154 void SwDoGetCapitalSize::Init( SwFntObj *, SwFntObj * )
155 {
156 	aTxtSize.Height() = 0;
157 	aTxtSize.Width() = 0;
158 }
159 
Do()160 void SwDoGetCapitalSize::Do()
161 {
162 	aTxtSize.Width() += rInf.GetSize().Width();
163 	if( rInf.GetUpper() )
164 		aTxtSize.Height() = rInf.GetSize().Height();
165 }
166 
167 /*************************************************************************
168  *					  SwSubFont::GetCapitalSize()
169  *************************************************************************/
170 
GetCapitalSize(SwDrawTextInfo & rInf)171 Size SwSubFont::GetCapitalSize( SwDrawTextInfo& rInf )
172 {
173 	// Start:
174     const long nOldKern = rInf.GetKern();
175 	rInf.SetKern( CheckKerning() );
176 	Point aPos;
177 	rInf.SetPos( aPos );
178 	rInf.SetSpace( 0 );
179 	rInf.SetDrawSpace( sal_False );
180 	SwDoGetCapitalSize aDo( rInf );
181 	DoOnCapitals( aDo );
182 	Size aTxtSize( aDo.GetSize() );
183 
184 	// End:
185 	if( !aTxtSize.Height() )
186 	{
187 		SV_STAT( nGetTextSize );
188 		aTxtSize.Height() = short ( rInf.GetpOut()->GetTextHeight() );
189 	}
190 	rInf.SetKern( nOldKern );
191 	return aTxtSize;
192 }
193 
194 /*************************************************************************
195  *					  class SwDoGetCapitalBreak
196  *************************************************************************/
197 
198 class SwDoGetCapitalBreak : public SwDoCapitals
199 {
200 protected:
201 	xub_StrLen *pExtraPos;
202 	long nTxtWidth;
203 	xub_StrLen nBreak;
204 public:
SwDoGetCapitalBreak(SwDrawTextInfo & rInfo,long nWidth,xub_StrLen * pExtra)205 	SwDoGetCapitalBreak( SwDrawTextInfo &rInfo, long nWidth, xub_StrLen *pExtra)
206         :   SwDoCapitals ( rInfo ), pExtraPos( pExtra ), nTxtWidth( nWidth ),
207             nBreak( STRING_LEN )
208 		{ }
209 	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
210 	virtual void Do();
GetBreak() const211 	xub_StrLen GetBreak() const { return nBreak; }
212 };
213 
Init(SwFntObj *,SwFntObj *)214 void SwDoGetCapitalBreak::Init( SwFntObj *, SwFntObj * )
215 {
216 }
217 
Do()218 void SwDoGetCapitalBreak::Do()
219 {
220 	if ( nTxtWidth )
221 	{
222 		if ( rInf.GetSize().Width() < nTxtWidth )
223 			nTxtWidth -= rInf.GetSize().Width();
224 		else
225 		{
226 			xub_StrLen nEnd = rInf.GetEnd();
227 			if( pExtraPos )
228 			{
229                 nBreak = GetOut().GetTextBreak( rInf.GetText(), nTxtWidth, '-',
230 					 *pExtraPos, rInf.GetIdx(), rInf.GetLen(), rInf.GetKern() );
231 				if( *pExtraPos > nEnd )
232 					*pExtraPos = nEnd;
233 			}
234 			else
235                 nBreak = GetOut().GetTextBreak( rInf.GetText(), nTxtWidth,
236 							   rInf.GetIdx(), rInf.GetLen(), rInf.GetKern() );
237 
238 			if( nBreak > nEnd )
239 				nBreak = nEnd;
240 
241             // nBreak may be relative to the display string. It has to be
242             // calculated relative to the original string:
243             if ( GetCapInf()  )
244             {
245                 if ( GetCapInf()->nLen != rInf.GetLen() )
246                     nBreak = lcl_CalcCaseMap( *rInf.GetFont(),
247                                               GetCapInf()->rString,
248                                               GetCapInf()->nIdx,
249                                               GetCapInf()->nLen, nBreak );
250                 else
251                     nBreak = nBreak + GetCapInf()->nIdx;
252             }
253 
254 			nTxtWidth = 0;
255 		}
256 	}
257 }
258 
259 /*************************************************************************
260  *					  SwFont::GetCapitalBreak()
261  *************************************************************************/
262 
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)263 xub_StrLen SwFont::GetCapitalBreak( ViewShell* pSh, const OutputDevice* pOut,
264     const SwScriptInfo* pScript, const XubString& rTxt, long nTextWidth,
265 	xub_StrLen *pExtra,	const xub_StrLen nIdx, const xub_StrLen nLen )
266 {
267 	// Start:
268 	Point aPos( 0, 0 );
269 	SwDrawTextInfo aInfo(pSh, *(OutputDevice*)pOut, pScript, rTxt, nIdx, nLen,
270 		0, sal_False);
271 	aInfo.SetPos( aPos );
272 	aInfo.SetSpace( 0 );
273 	aInfo.SetWrong( NULL );
274     aInfo.SetGrammarCheck( NULL );
275     aInfo.SetSmartTags( NULL ); // SMARTTAGS
276     aInfo.SetDrawSpace( sal_False );
277 	aInfo.SetKern( CheckKerning() );
278 	aInfo.SetKanaComp( pScript ? 0 : 100 );
279     aInfo.SetFont( this );
280 
281 	SwDoGetCapitalBreak aDo( aInfo, nTextWidth, pExtra );
282 	DoOnCapitals( aDo );
283 	return aDo.GetBreak();
284 }
285 
286 /*************************************************************************
287  *					   class SwDoDrawCapital
288  *************************************************************************/
289 
290 class SwDoDrawCapital : public SwDoCapitals
291 {
292 protected:
293 	SwFntObj *pUpperFnt;
294 	SwFntObj *pLowerFnt;
295 public:
SwDoDrawCapital(SwDrawTextInfo & rInfo)296 	SwDoDrawCapital( SwDrawTextInfo &rInfo ) :
297 		SwDoCapitals( rInfo )
298 		{ }
299 	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
300 	virtual void Do();
301 	void DrawSpace( Point &rPos );
302 };
303 
Init(SwFntObj * pUpperFont,SwFntObj * pLowerFont)304 void SwDoDrawCapital::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
305 {
306 	pUpperFnt = pUpperFont;
307 	pLowerFnt = pLowerFont;
308 }
309 
Do()310 void SwDoDrawCapital::Do()
311 {
312 	SV_STAT( nDrawText );
313 	sal_uInt16 nOrgWidth = rInf.GetWidth();
314 	rInf.SetWidth( sal_uInt16(rInf.GetSize().Width()) );
315 	if ( rInf.GetUpper() )
316 		pUpperFnt->DrawText( rInf );
317 	else
318 	{
319 		sal_Bool bOldBullet = rInf.GetBullet();
320 		rInf.SetBullet( sal_False );
321 		pLowerFnt->DrawText( rInf );
322 		rInf.SetBullet( bOldBullet );
323 	}
324 
325     ASSERT( pUpperFnt, "No upper font, dying soon!");
326     rInf.Shift( pUpperFnt->GetFont()->GetOrientation() );
327 	rInf.SetWidth( nOrgWidth );
328 }
329 
330 /*************************************************************************
331  *					  SwDoDrawCapital::DrawSpace()
332  *************************************************************************/
333 
DrawSpace(Point & rPos)334 void SwDoDrawCapital::DrawSpace( Point &rPos )
335 {
336 	static sal_Char __READONLY_DATA sDoubleSpace[] = "  ";
337 
338     long nDiff = rInf.GetPos().X() - rPos.X();
339 
340     Point aPos( rPos );
341     const sal_Bool bSwitchL2R = rInf.GetFrm()->IsRightToLeft() &&
342                           ! rInf.IsIgnoreFrmRTL();
343 
344 
345     if ( bSwitchL2R )
346        rInf.GetFrm()->SwitchLTRtoRTL( aPos );
347 
348     const sal_uLong nMode = rInf.GetpOut()->GetLayoutMode();
349     const sal_Bool bBidiPor = ( bSwitchL2R !=
350                             ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) );
351 
352     if ( bBidiPor )
353         nDiff = -nDiff;
354 
355     if ( rInf.GetFrm()->IsVertical() )
356         rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
357 
358 	if ( nDiff )
359     {
360         rInf.ApplyAutoColor();
361         GetOut().DrawStretchText( aPos, nDiff,
362 			XubString( sDoubleSpace, RTL_TEXTENCODING_MS_1252 ), 0, 2 );
363     }
364 	rPos.X() = rInf.GetPos().X() + rInf.GetWidth();
365 }
366 
367 /*************************************************************************
368  *					  SwSubFont::DrawCapital()
369  *************************************************************************/
370 
DrawCapital(SwDrawTextInfo & rInf)371 void SwSubFont::DrawCapital( SwDrawTextInfo &rInf )
372 {
373 	// Es wird vorausgesetzt, dass rPos bereits kalkuliert ist!
374 	// hochgezogen in SwFont: const Point aPos( CalcPos(rPos) );
375 	rInf.SetDrawSpace( GetUnderline() != UNDERLINE_NONE ||
376 					   GetOverline()  != UNDERLINE_NONE ||
377 					   GetStrikeout() != STRIKEOUT_NONE );
378 	SwDoDrawCapital aDo( rInf );
379 	DoOnCapitals( aDo );
380 }
381 
382 /*************************************************************************
383  *					   class SwDoDrawCapital
384  *************************************************************************/
385 
386 class SwDoCapitalCrsrOfst : public SwDoCapitals
387 {
388 protected:
389 	SwFntObj *pUpperFnt;
390 	SwFntObj *pLowerFnt;
391 	xub_StrLen nCrsr;
392 	sal_uInt16 nOfst;
393 public:
SwDoCapitalCrsrOfst(SwDrawTextInfo & rInfo,const sal_uInt16 nOfs)394 	SwDoCapitalCrsrOfst( SwDrawTextInfo &rInfo, const sal_uInt16 nOfs ) :
395         SwDoCapitals( rInfo ), nCrsr( 0 ), nOfst( nOfs )
396 		{ }
397 	virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
398 	virtual void Do();
399 
400 	void DrawSpace( const Point &rPos );
GetCrsr()401 	inline xub_StrLen GetCrsr(){ return nCrsr; }
402 };
403 
Init(SwFntObj * pUpperFont,SwFntObj * pLowerFont)404 void SwDoCapitalCrsrOfst::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
405 {
406 	pUpperFnt = pUpperFont;
407 	pLowerFnt = pLowerFont;
408 }
409 
Do()410 void SwDoCapitalCrsrOfst::Do()
411 {
412 	if ( nOfst )
413 	{
414 		if ( nOfst > rInf.GetSize().Width() )
415 		{
416 			nOfst = nOfst - sal_uInt16(rInf.GetSize().Width());
417 			nCrsr = nCrsr + rInf.GetLen();
418 		}
419 		else
420 		{
421             SwDrawTextInfo aDrawInf( rInf.GetShell(), *rInf.GetpOut(),
422                                      rInf.GetScriptInfo(),
423                                      rInf.GetText(),
424                                      rInf.GetIdx(),
425                                      rInf.GetLen(), 0, sal_False );
426             aDrawInf.SetOfst( nOfst );
427             aDrawInf.SetKern( rInf.GetKern() );
428             aDrawInf.SetKanaComp( rInf.GetKanaComp() );
429             aDrawInf.SetFrm( rInf.GetFrm() );
430             aDrawInf.SetFont( rInf.GetFont() );
431 
432 			if ( rInf.GetUpper() )
433             {
434                 aDrawInf.SetSpace( 0 );
435                 nCrsr = nCrsr + pUpperFnt->GetCrsrOfst( aDrawInf );
436             }
437 			else
438             {
439                 aDrawInf.SetSpace( rInf.GetSpace() );
440                 nCrsr = nCrsr + pLowerFnt->GetCrsrOfst( aDrawInf );
441             }
442             nOfst = 0;
443 		}
444 	}
445 }
446 
447 /*************************************************************************
448  *					  SwSubFont::GetCapitalCrsrOfst()
449  *************************************************************************/
450 
GetCapitalCrsrOfst(SwDrawTextInfo & rInf)451 xub_StrLen SwSubFont::GetCapitalCrsrOfst( SwDrawTextInfo& rInf )
452 {
453     const long nOldKern = rInf.GetKern();
454 	rInf.SetKern( CheckKerning() );
455 	SwDoCapitalCrsrOfst aDo( rInf, rInf.GetOfst() );
456 	Point aPos;
457 	rInf.SetPos( aPos );
458 	rInf.SetDrawSpace( sal_False );
459 	DoOnCapitals( aDo );
460 	rInf.SetKern( nOldKern );
461 	return aDo.GetCrsr();
462 }
463 
464 /*************************************************************************
465  *					  class SwDoDrawStretchCapital
466  *************************************************************************/
467 
468 class SwDoDrawStretchCapital : public SwDoDrawCapital
469 {
470 	const xub_StrLen nStrLen;
471 	const sal_uInt16 nCapWidth;
472 	const sal_uInt16 nOrgWidth;
473 public:
474 	virtual void Do();
475 
SwDoDrawStretchCapital(SwDrawTextInfo & rInfo,const sal_uInt16 nCapitalWidth)476     SwDoDrawStretchCapital( SwDrawTextInfo &rInfo, const sal_uInt16 nCapitalWidth )
477 			: SwDoDrawCapital( rInfo ),
478               nStrLen( rInfo.GetLen() ),
479               nCapWidth( nCapitalWidth ),
480               nOrgWidth( rInfo.GetWidth() )
481         { }
482 };
483 
484 /*************************************************************************
485  *					  SwDoDrawStretchCapital
486  *************************************************************************/
487 
Do()488 void SwDoDrawStretchCapital::Do()
489 {
490 	SV_STAT( nDrawStretchText );
491 	sal_uInt16 nPartWidth = sal_uInt16(rInf.GetSize().Width());
492 
493 	if( rInf.GetLen() )
494 	{
495 		// 4023: Kapitaelchen und Kerning.
496 		long nDiff = long(nOrgWidth) - long(nCapWidth);
497 		if( nDiff )
498 		{
499 			nDiff *= rInf.GetLen();
500 			nDiff /= (long) nStrLen;
501 			nDiff += nPartWidth;
502 			if( 0 < nDiff )
503 				nPartWidth = sal_uInt16(nDiff);
504 		}
505 
506         rInf.ApplyAutoColor();
507 
508         Point aPos( rInf.GetPos() );
509         const sal_Bool bSwitchL2R = rInf.GetFrm()->IsRightToLeft() &&
510                               ! rInf.IsIgnoreFrmRTL();
511 
512         if ( bSwitchL2R )
513             rInf.GetFrm()->SwitchLTRtoRTL( aPos );
514 
515         if ( rInf.GetFrm()->IsVertical() )
516             rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
517 
518         // Optimierung:
519         if( 1 >= rInf.GetLen() )
520             GetOut().DrawText( aPos, rInf.GetText(), rInf.GetIdx(),
521 				rInf.GetLen() );
522 		else
523             GetOut().DrawStretchText( aPos, nPartWidth,
524 								rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
525 	}
526 	((Point&)rInf.GetPos()).X() += nPartWidth;
527 }
528 
529 /*************************************************************************
530  *					  SwSubFont::DrawStretchCapital()
531  *************************************************************************/
532 
DrawStretchCapital(SwDrawTextInfo & rInf)533 void SwSubFont::DrawStretchCapital( SwDrawTextInfo &rInf )
534 {
535 	// Es wird vorausgesetzt, dass rPos bereits kalkuliert ist!
536 	// hochgezogen in SwFont: const Point aPos( CalcPos(rPos) );
537 
538 	if( rInf.GetLen() == STRING_LEN )
539 		rInf.SetLen( rInf.GetText().Len() );
540 
541     const Point& rOldPos = rInf.GetPos();
542 	const sal_uInt16 nCapWidth = (sal_uInt16)( GetCapitalSize( rInf ).Width() );
543     rInf.SetPos( rOldPos );
544 
545 	rInf.SetDrawSpace( GetUnderline() != UNDERLINE_NONE ||
546 					   GetOverline()  != UNDERLINE_NONE ||
547 					   GetStrikeout() != STRIKEOUT_NONE );
548 	SwDoDrawStretchCapital aDo( rInf, nCapWidth );
549 	DoOnCapitals( aDo );
550 }
551 
552 /*************************************************************************
553  *					SwSubFont::DoOnCapitals() const
554  *************************************************************************/
555 
556 // JP 22.8.2001 - global optimization off - Bug 91245 / 91223
557 #ifdef _MSC_VER
558 #pragma optimize("g",off)
559 #endif
560 
DoOnCapitals(SwDoCapitals & rDo)561 void SwSubFont::DoOnCapitals( SwDoCapitals &rDo )
562 {
563 	ASSERT( pLastFont, "SwFont::DoOnCapitals: No LastFont?!" );
564 
565 	Size aPartSize;
566 	long nKana = 0;
567 	const XubString aTxt( CalcCaseMap( rDo.GetInf().GetText() ) );
568 	xub_StrLen nMaxPos = Min( sal_uInt16(rDo.GetInf().GetText().Len()
569 							- rDo.GetInf().GetIdx()), rDo.GetInf().GetLen() );
570 	rDo.GetInf().SetLen( nMaxPos );
571 
572 	const XubString& rOldText = rDo.GetInf().GetText();
573 	rDo.GetInf().SetText( aTxt );
574 	rDo.GetInf().SetSize( aPartSize );
575 	xub_StrLen nPos = rDo.GetInf().GetIdx();
576 	xub_StrLen nOldPos = nPos;
577 	nMaxPos = nMaxPos + nPos;
578 
579 	// #107816#
580 	// Look if the length of the original text and the ToUpper-converted
581 	// text is different. If yes, do special handling.
582     XubString aNewText;
583     SwCapitalInfo aCapInf( rOldText );
584     sal_Bool bCaseMapLengthDiffers( aTxt.Len() != rOldText.Len() );
585     if ( bCaseMapLengthDiffers )
586         rDo.SetCapInf( aCapInf );
587 
588 	SwFntObj *pOldLast = pLastFont;
589 	SwFntAccess *pBigFontAccess = NULL;
590 	SwFntObj *pBigFont;
591 	SwFntAccess *pSpaceFontAccess = NULL;
592 	SwFntObj *pSpaceFont = NULL;
593 
594 	const void *pMagic2 = NULL;
595 	sal_uInt16 nIndex2 = 0;
596 	SwSubFont aFont( *this );
597 	Point aStartPos( rDo.GetInf().GetPos() );
598 
599 	const sal_Bool bTextLines = aFont.GetUnderline() != UNDERLINE_NONE
600 						 || aFont.GetOverline()  != UNDERLINE_NONE
601 						 || aFont.GetStrikeout() != STRIKEOUT_NONE;
602 	const sal_Bool bWordWise = bTextLines && aFont.IsWordLineMode() &&
603 						   rDo.GetInf().GetDrawSpace();
604     const long nTmpKern = rDo.GetInf().GetKern();
605 
606 	if ( bTextLines )
607 	{
608 		if ( bWordWise )
609 		{
610 			aFont.SetWordLineMode( sal_False );
611 			pSpaceFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
612 												rDo.GetInf().GetShell() );
613 			pSpaceFont = pSpaceFontAccess->Get();
614 		}
615 		else
616 			pSpaceFont = pLastFont;
617 
618 		// Wir basteln uns einen Font fuer die Grossbuchstaben:
619 		aFont.SetUnderline( UNDERLINE_NONE );
620 		aFont.SetOverline( UNDERLINE_NONE );
621 		aFont.SetStrikeout( STRIKEOUT_NONE );
622 		pMagic2 = NULL;
623 		nIndex2 = 0;
624 		pBigFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
625 										  rDo.GetInf().GetShell() );
626 		pBigFont = pBigFontAccess->Get();
627 	}
628 	else
629 		pBigFont = pLastFont;
630 
631 	// Hier entsteht der Kleinbuchstabenfont:
632 	aFont.SetProportion( sal_uInt8( (aFont.GetPropr()*KAPITAELCHENPROP) / 100L) );
633 	pMagic2 = NULL;
634 	nIndex2 = 0;
635 	SwFntAccess *pSmallFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
636 													 rDo.GetInf().GetShell() );
637 	SwFntObj *pSmallFont = pSmallFontAccess->Get();
638 
639 	rDo.Init( pBigFont, pSmallFont );
640 	OutputDevice* pOutSize = pSmallFont->GetPrt();
641 	if( !pOutSize )
642         pOutSize = &rDo.GetOut();
643     OutputDevice* pOldOut = &rDo.GetOut();
644 
645 	const LanguageType eLng = LANGUAGE_DONTKNOW == GetLanguage()
646 							? LANGUAGE_SYSTEM : GetLanguage();
647 
648 	if( nPos < nMaxPos )
649 	{
650 		nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfCharBlock( rOldText, nPos,
651 			pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
652 		if( nPos == STRING_LEN )
653 			nPos = nOldPos;
654 		else if( nPos > nMaxPos )
655 			nPos = nMaxPos;
656 	}
657 
658 	while( nOldPos < nMaxPos )
659 	{
660 
661 		//  The lower ones...
662 		if( nOldPos != nPos )
663 		{
664 			SV_STAT( nGetTextSize );
665 			pLastFont = pSmallFont;
666 			pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
667 
668 			// #107816#, #i14820#
669             if( bCaseMapLengthDiffers )
670             {
671                 // Build an own 'changed' string for the given part of the
672                 // source string and use it. That new string may differ in length
673                 // from the source string.
674                 const XubString aSnippet( rOldText, nOldPos, nPos - nOldPos);
675                 aNewText = CalcCaseMap( aSnippet );
676                 aCapInf.nIdx = nOldPos;
677                 aCapInf.nLen = nPos - nOldPos;
678                 rDo.GetInf().SetIdx( 0 );
679                 rDo.GetInf().SetLen( aNewText.Len() );
680                 rDo.GetInf().SetText( aNewText );
681             }
682             else
683             {
684                 rDo.GetInf().SetIdx( nOldPos );
685                 rDo.GetInf().SetLen( nPos - nOldPos );
686             }
687 
688 			rDo.GetInf().SetUpper( sal_False );
689 			rDo.GetInf().SetOut( *pOutSize );
690 			aPartSize = pSmallFont->GetTextSize( rDo.GetInf() );
691 			nKana += rDo.GetInf().GetKanaDiff();
692 			rDo.GetInf().SetOut( *pOldOut );
693             if( nTmpKern && nPos < nMaxPos )
694                 aPartSize.Width() += nTmpKern;
695 			rDo.Do();
696 			nOldPos = nPos;
697 		}
698 		nPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharBlock( rOldText, nPos,
699 			   pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
700 		if( nPos == STRING_LEN || nPos > nMaxPos )
701 			nPos = nMaxPos;
702 		ASSERT( nPos, "nextCharBlock not implemented?" );
703 #ifdef DBG_UTIL
704 		if( !nPos )
705 			nPos = nMaxPos;
706 #endif
707 		// The upper ones...
708 		if( nOldPos != nPos )
709 		{
710             const long nSpaceAdd = rDo.GetInf().GetSpace() / SPACING_PRECISION_FACTOR;
711 
712             do
713 			{
714 				rDo.GetInf().SetUpper( sal_True );
715 				pLastFont = pBigFont;
716 				pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
717 				xub_StrLen nTmp;
718 				if( bWordWise )
719 				{
720 					nTmp = nOldPos;
721 					while( nTmp < nPos && CH_BLANK == rOldText.GetChar( nTmp ) )
722 						++nTmp;
723 					if( nOldPos < nTmp )
724 					{
725 						pLastFont = pSpaceFont;
726 						pLastFont->SetDevFont( rDo.GetInf().GetShell(),
727 											   rDo.GetOut() );
728 						((SwDoDrawCapital&)rDo).DrawSpace( aStartPos );
729 						pLastFont = pBigFont;
730 						pLastFont->SetDevFont( rDo.GetInf().GetShell(),
731 											   rDo.GetOut() );
732 
733 			            // #107816#, #i14820#
734                         if( bCaseMapLengthDiffers )
735                         {
736                             // Build an own 'changed' string for the given part of the
737                             // source string and use it. That new string may differ in length
738                             // from the source string.
739                             const XubString aSnippet( rOldText, nOldPos, nTmp - nOldPos);
740                             aNewText = CalcCaseMap( aSnippet );
741                             aCapInf.nIdx = nOldPos;
742                             aCapInf.nLen = nTmp - nOldPos;
743                             rDo.GetInf().SetIdx( 0 );
744                             rDo.GetInf().SetLen( aNewText.Len() );
745                             rDo.GetInf().SetText( aNewText );
746                         }
747                         else
748                         {
749                             rDo.GetInf().SetIdx( nOldPos );
750                             rDo.GetInf().SetLen( nTmp - nOldPos );
751                         }
752 
753 						rDo.GetInf().SetOut( *pOutSize );
754 						aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
755 						nKana += rDo.GetInf().GetKanaDiff();
756 						rDo.GetInf().SetOut( *pOldOut );
757                         if( nSpaceAdd )
758                             aPartSize.Width() += nSpaceAdd * ( nTmp - nOldPos );
759                         if( nTmpKern && nPos < nMaxPos )
760                             aPartSize.Width() += nTmpKern;
761 						rDo.Do();
762 						aStartPos = rDo.GetInf().GetPos();
763 						nOldPos = nTmp;
764 					}
765 
766                     while( nTmp < nPos && CH_BLANK != rOldText.GetChar( nTmp ) )
767 						++nTmp;
768 				}
769 				else
770 					nTmp = nPos;
771 				if( nTmp > nOldPos )
772 				{
773           			// #107816#, #i14820#
774                     if( bCaseMapLengthDiffers )
775                     {
776                         // Build an own 'changed' string for the given part of the
777                         // source string and use it. That new string may differ in length
778                         // from the source string.
779                         const XubString aSnippet( rOldText, nOldPos, nTmp - nOldPos);
780                         aNewText = CalcCaseMap( aSnippet );
781                         aCapInf.nIdx = nOldPos;
782                         aCapInf.nLen = nTmp - nOldPos;
783                         rDo.GetInf().SetIdx( 0 );
784                         rDo.GetInf().SetLen( aNewText.Len() );
785                         rDo.GetInf().SetText( aNewText );
786                     }
787                     else
788                     {
789                         rDo.GetInf().SetIdx( nOldPos );
790                         rDo.GetInf().SetLen( nTmp - nOldPos );
791                     }
792 
793 					rDo.GetInf().SetOut( *pOutSize );
794 					aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
795 					nKana += rDo.GetInf().GetKanaDiff();
796 					rDo.GetInf().SetOut( *pOldOut );
797 					if( !bWordWise && rDo.GetInf().GetSpace() )
798                     {
799                         for( xub_StrLen nI = nOldPos; nI < nPos; ++nI )
800                         {
801 							if( CH_BLANK == rOldText.GetChar( nI ) )
802                                 aPartSize.Width() += nSpaceAdd;
803                         }
804                     }
805                     if( nTmpKern && nPos < nMaxPos )
806                         aPartSize.Width() += nTmpKern;
807 					rDo.Do();
808 					nOldPos = nTmp;
809 				}
810 			} while( nOldPos != nPos );
811 		}
812 		nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfCharBlock( rOldText, nPos,
813 			   pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
814 		if( nPos == STRING_LEN || nPos > nMaxPos )
815 			nPos = nMaxPos;
816 		ASSERT( nPos, "endOfCharBlock not implemented?" );
817 #ifdef DBG_UTIL
818 		if( !nPos )
819 			nPos = nMaxPos;
820 #endif
821 	}
822 
823 	// Aufraeumen:
824 	if( pBigFont != pOldLast )
825 		delete pBigFontAccess;
826 
827 	if( bTextLines )
828 	{
829 		if( rDo.GetInf().GetDrawSpace() )
830 		{
831 			pLastFont = pSpaceFont;
832 			pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
833 			( (SwDoDrawCapital&) rDo ).DrawSpace( aStartPos );
834 		}
835 		if ( bWordWise )
836 			delete pSpaceFontAccess;
837 	}
838 	pLastFont =	pOldLast;
839 	pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
840 
841 	delete pSmallFontAccess;
842 	rDo.GetInf().SetText( rOldText );
843 	rDo.GetInf().SetKanaDiff( nKana );
844 }
845 
846 // JP 22.8.2001 - global optimization off - Bug 91245 / 91223
847 #ifdef _MSC_VER
848 #pragma optimize("g",on)
849 #endif
850 
851 
852