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