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