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