xref: /trunk/main/sw/source/core/txtnode/fntcap.cxx (revision cd519653a6b6a9e2ff38774da567b1ae7cbeddbb)
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 74
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