Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <comphelper/string.hxx>
21 : #include <vcl/outdev.hxx>
22 : #include <vcl/print.hxx>
23 : #include <tools/gen.hxx>
24 : #include <tools/poly.hxx>
25 : #include <unotools/charclass.hxx>
26 : #include <editeng/unolingu.hxx>
27 : #include <com/sun/star/i18n/KCharacterType.hpp>
28 : #include <editeng/svxfont.hxx>
29 : #include <editeng/escapementitem.hxx>
30 :
31 : const sal_Unicode CH_BLANK = ' '; // ' ' Space character
32 :
33 :
34 0 : SvxFont::SvxFont()
35 : {
36 0 : nKern = nEsc = 0;
37 0 : nPropr = 100;
38 0 : eCaseMap = SVX_CASEMAP_NOT_MAPPED;
39 0 : SetLanguage(LANGUAGE_SYSTEM);
40 0 : }
41 :
42 0 : SvxFont::SvxFont( const Font &rFont )
43 0 : : Font( rFont )
44 : {
45 0 : nKern = nEsc = 0;
46 0 : nPropr = 100;
47 0 : eCaseMap = SVX_CASEMAP_NOT_MAPPED;
48 0 : SetLanguage(LANGUAGE_SYSTEM);
49 0 : }
50 :
51 0 : SvxFont::SvxFont( const SvxFont &rFont )
52 0 : : Font( rFont )
53 : {
54 0 : nKern = rFont.GetFixKerning();
55 0 : nEsc = rFont.GetEscapement();
56 0 : nPropr = rFont.GetPropr();
57 0 : eCaseMap = rFont.GetCaseMap();
58 0 : SetLanguage(rFont.GetLanguage());
59 0 : }
60 :
61 0 : void SvxFont::DrawArrow( OutputDevice &rOut, const Rectangle& rRect,
62 : const Size& rSize, const Color& rCol, bool bLeft )
63 : {
64 0 : long nLeft = ( rRect.Left() + rRect.Right() - rSize.Width() )/ 2;
65 0 : long nRight = nLeft + rSize.Width();
66 0 : long nMid = ( rRect.Top() + rRect.Bottom() ) / 2;
67 0 : long nTop = nMid - rSize.Height() / 2;
68 0 : long nBottom = nTop + rSize.Height();
69 0 : if( nLeft < rRect.Left() )
70 : {
71 0 : nLeft = rRect.Left();
72 0 : nRight = rRect.Right();
73 : }
74 0 : if( nTop < rRect.Top() )
75 : {
76 0 : nTop = rRect.Top();
77 0 : nBottom = rRect.Bottom();
78 : }
79 0 : Polygon aPoly;
80 0 : Point aTmp( bLeft ? nLeft : nRight, nMid );
81 0 : Point aNxt( bLeft ? nRight : nLeft, nTop );
82 0 : aPoly.Insert( 0, aTmp );
83 0 : aPoly.Insert( 0, aNxt );
84 0 : aNxt.Y() = nBottom;
85 0 : aPoly.Insert( 0, aNxt );
86 0 : aPoly.Insert( 0, aTmp );
87 0 : Color aOldLineColor = rOut.GetLineColor();
88 0 : Color aOldFillColor = rOut.GetFillColor();
89 0 : rOut.SetFillColor( rCol );
90 0 : rOut.SetLineColor( Color( COL_BLACK ) );
91 0 : rOut.DrawPolygon( aPoly );
92 0 : rOut.DrawLine( aTmp, aNxt );
93 0 : rOut.SetLineColor( aOldLineColor );
94 0 : rOut.SetFillColor( aOldFillColor );
95 0 : }
96 :
97 :
98 0 : OUString SvxFont::CalcCaseMap(const OUString &rTxt) const
99 : {
100 0 : if (!IsCaseMap() || rTxt.isEmpty())
101 0 : return rTxt;
102 0 : OUString aTxt(rTxt);
103 : // I still have to get the language
104 0 : const LanguageType eLang = LANGUAGE_DONTKNOW == GetLanguage()
105 0 : ? LANGUAGE_SYSTEM : GetLanguage();
106 :
107 0 : LanguageTag aLanguageTag(eLang);
108 0 : CharClass aCharClass( aLanguageTag );
109 :
110 0 : switch( eCaseMap )
111 : {
112 : case SVX_CASEMAP_KAPITAELCHEN:
113 : case SVX_CASEMAP_VERSALIEN:
114 : {
115 0 : aTxt = aCharClass.uppercase( aTxt );
116 0 : break;
117 : }
118 :
119 : case SVX_CASEMAP_GEMEINE:
120 : {
121 0 : aTxt = aCharClass.lowercase( aTxt );
122 0 : break;
123 : }
124 : case SVX_CASEMAP_TITEL:
125 : {
126 : // Every beginning of a word is capitalized, the rest of the word
127 : // is taken over as is.
128 : // Bug: if the attribute starts in the middle of the word.
129 0 : bool bBlank = true;
130 :
131 0 : for (sal_Int32 i = 0; i < aTxt.getLength(); ++i)
132 : {
133 0 : if( aTxt[i] == ' ' || aTxt[i] == '\t')
134 0 : bBlank = true;
135 : else
136 : {
137 0 : if (bBlank)
138 : {
139 0 : OUString sTitle(aCharClass.uppercase(OUString(aTxt[i])));
140 0 : aTxt = aTxt.replaceAt(i, 1, sTitle);
141 : }
142 0 : bBlank = false;
143 : }
144 : }
145 0 : break;
146 : }
147 : default:
148 : {
149 : DBG_ASSERT(!this, "SvxFont::CaseMapTxt: unknown casemap");
150 0 : break;
151 : }
152 : }
153 0 : return aTxt;
154 : }
155 :
156 : /*************************************************************************
157 : * class SvxDoCapitals
158 : * The virtual Method Do si called by SvxFont::DoOnCapitals alternately
159 : * the uppercase and lowercase parts. The derivate of SvxDoCapitals fills
160 : * this method with life.
161 : *************************************************************************/
162 :
163 : class SvxDoCapitals
164 : {
165 : protected:
166 : OutputDevice *pOut;
167 : const OUString &rTxt;
168 : const sal_Int32 nIdx;
169 : const sal_Int32 nLen;
170 :
171 : public:
172 0 : SvxDoCapitals( OutputDevice *_pOut, const OUString &_rTxt,
173 : const sal_Int32 _nIdx, const sal_Int32 _nLen )
174 0 : : pOut(_pOut), rTxt(_rTxt), nIdx(_nIdx), nLen(_nLen)
175 0 : { }
176 :
177 0 : virtual ~SvxDoCapitals() {}
178 :
179 : virtual void DoSpace( const sal_Bool bDraw );
180 : virtual void SetSpace();
181 : virtual void Do( const OUString &rTxt,
182 : const sal_Int32 nIdx, const sal_Int32 nLen,
183 : const sal_Bool bUpper ) = 0;
184 :
185 0 : const OUString &GetTxt() const { return rTxt; }
186 0 : sal_Int32 GetIdx() const { return nIdx; }
187 0 : sal_Int32 GetLen() const { return nLen; }
188 : };
189 :
190 0 : void SvxDoCapitals::DoSpace( const sal_Bool /*bDraw*/ ) { }
191 :
192 0 : void SvxDoCapitals::SetSpace() { }
193 :
194 : /*************************************************************************
195 : * SvxFont::DoOnCapitals() const
196 : * Decomposes the String into uppercase and lowercase letters and then
197 : * calls the method SvxDoCapitals::Do( ).
198 : *************************************************************************/
199 :
200 0 : void SvxFont::DoOnCapitals(SvxDoCapitals &rDo) const
201 : {
202 0 : const OUString &rTxt = rDo.GetTxt();
203 0 : const sal_Int32 nIdx = rDo.GetIdx();
204 0 : const sal_Int32 nLen = rDo.GetLen();
205 :
206 0 : const OUString aTxt( CalcCaseMap( rTxt ) );
207 0 : const sal_Int32 nTxtLen = std::min( rTxt.getLength(), nLen );
208 0 : sal_Int32 nPos = 0;
209 0 : sal_Int32 nOldPos = nPos;
210 :
211 : // #108210#
212 : // Test if string length differ between original and CaseMapped
213 0 : sal_Bool bCaseMapLengthDiffers(aTxt.getLength() != rTxt.getLength());
214 :
215 0 : const LanguageType eLang = LANGUAGE_DONTKNOW == GetLanguage()
216 0 : ? LANGUAGE_SYSTEM : GetLanguage();
217 :
218 0 : LanguageTag aLanguageTag(eLang);
219 0 : CharClass aCharClass( aLanguageTag );
220 0 : OUString aCharString;
221 :
222 0 : while( nPos < nTxtLen )
223 : {
224 : // first in turn are the uppercase letters
225 :
226 : // There are characters that are both upper- and lower-case L (eg blank)
227 : // Such ambiguities lead to chaos, this is why these characters are
228 : // allocated to the lowercase characters!
229 :
230 0 : while( nPos < nTxtLen )
231 : {
232 0 : aCharString = rTxt.copy( nPos + nIdx, 1 );
233 0 : sal_Int32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
234 0 : if ( nCharacterType & ::com::sun::star::i18n::KCharacterType::LOWER )
235 0 : break;
236 0 : if ( ! ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) )
237 0 : break;
238 0 : ++nPos;
239 : }
240 0 : if( nOldPos != nPos )
241 : {
242 0 : if(bCaseMapLengthDiffers)
243 : {
244 : // #108210#
245 : // If strings differ work preparing the necessary snippet to address that
246 : // potential difference
247 0 : const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos-nOldPos);
248 0 : OUString aNewText = CalcCaseMap(aSnippet);
249 :
250 0 : rDo.Do( aNewText, 0, aNewText.getLength(), sal_True );
251 : }
252 : else
253 : {
254 0 : rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, sal_True );
255 : }
256 :
257 0 : nOldPos = nPos;
258 : }
259 : // Now the lowercase are processed (without blanks)
260 0 : while( nPos < nTxtLen )
261 : {
262 0 : sal_uInt32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
263 0 : if ( ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) )
264 0 : break;
265 0 : if ( comphelper::string::equals(aCharString, CH_BLANK) )
266 0 : break;
267 0 : if( ++nPos < nTxtLen )
268 0 : aCharString = rTxt.copy( nPos + nIdx, 1 );
269 : }
270 0 : if( nOldPos != nPos )
271 : {
272 0 : if(bCaseMapLengthDiffers)
273 : {
274 : // #108210#
275 : // If strings differ work preparing the necessary snippet to address that
276 : // potential difference
277 0 : const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos - nOldPos);
278 0 : OUString aNewText = CalcCaseMap(aSnippet);
279 :
280 0 : rDo.Do( aNewText, 0, aNewText.getLength(), sal_False );
281 : }
282 : else
283 : {
284 0 : rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, sal_False );
285 : }
286 :
287 0 : nOldPos = nPos;
288 : }
289 : // Now the blanks are<processed
290 0 : while( nPos < nTxtLen && comphelper::string::equals(aCharString, CH_BLANK) && ++nPos < nTxtLen )
291 0 : aCharString = rTxt.copy( nPos + nIdx, 1 );
292 :
293 0 : if( nOldPos != nPos )
294 : {
295 0 : rDo.DoSpace( sal_False );
296 :
297 0 : if(bCaseMapLengthDiffers)
298 : {
299 : // #108210#
300 : // If strings differ work preparing the necessary snippet to address that
301 : // potential difference
302 0 : const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos - nOldPos);
303 0 : OUString aNewText = CalcCaseMap(aSnippet);
304 :
305 0 : rDo.Do( aNewText, 0, aNewText.getLength(), sal_False );
306 : }
307 : else
308 : {
309 0 : rDo.Do( aTxt, nIdx + nOldPos, nPos - nOldPos, sal_False );
310 : }
311 :
312 0 : nOldPos = nPos;
313 0 : rDo.SetSpace();
314 : }
315 : }
316 0 : rDo.DoSpace( sal_True );
317 0 : }
318 :
319 :
320 0 : void SvxFont::SetPhysFont( OutputDevice *pOut ) const
321 : {
322 0 : const Font& rCurrentFont = pOut->GetFont();
323 0 : if ( nPropr == 100 )
324 : {
325 0 : if ( !rCurrentFont.IsSameInstance( *this ) )
326 0 : pOut->SetFont( *this );
327 : }
328 : else
329 : {
330 0 : Font aNewFont( *this );
331 0 : Size aSize( aNewFont.GetSize() );
332 0 : aNewFont.SetSize( Size( aSize.Width() * nPropr / 100L,
333 0 : aSize.Height() * nPropr / 100L ) );
334 0 : if ( !rCurrentFont.IsSameInstance( aNewFont ) )
335 0 : pOut->SetFont( aNewFont );
336 : }
337 0 : }
338 :
339 :
340 0 : Font SvxFont::ChgPhysFont( OutputDevice *pOut ) const
341 : {
342 0 : Font aOldFont( pOut->GetFont() );
343 0 : SetPhysFont( pOut );
344 0 : return aOldFont;
345 : }
346 :
347 :
348 0 : Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const OUString &rTxt,
349 : const sal_Int32 nIdx, const sal_Int32 nLen ) const
350 : {
351 0 : if ( !IsCaseMap() && !IsKern() )
352 : return Size( pOut->GetTextWidth( rTxt, nIdx, nLen ),
353 0 : pOut->GetTextHeight() );
354 :
355 0 : Size aTxtSize;
356 0 : aTxtSize.setHeight( pOut->GetTextHeight() );
357 0 : if ( !IsCaseMap() )
358 0 : aTxtSize.setWidth( pOut->GetTextWidth( rTxt, nIdx, nLen ) );
359 : else
360 : {
361 : // #108210#
362 0 : const OUString aNewText = CalcCaseMap(rTxt);
363 0 : sal_Bool bCaseMapLengthDiffers(aNewText.getLength() != rTxt.getLength());
364 0 : sal_Int32 nWidth(0L);
365 :
366 0 : if(bCaseMapLengthDiffers)
367 : {
368 : // If strings differ work preparing the necessary snippet to address that
369 : // potential difference
370 0 : const OUString aSnippet = rTxt.copy(nIdx, nLen);
371 0 : OUString _aNewText = CalcCaseMap(aSnippet);
372 0 : nWidth = pOut->GetTextWidth( _aNewText, 0, _aNewText.getLength() );
373 : }
374 : else
375 : {
376 0 : nWidth = pOut->GetTextWidth( aNewText, nIdx, nLen );
377 : }
378 :
379 0 : aTxtSize.setWidth(nWidth);
380 : }
381 :
382 0 : if( IsKern() && ( nLen > 1 ) )
383 0 : aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) );
384 :
385 0 : return aTxtSize;
386 : }
387 :
388 0 : Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const OUString &rTxt )
389 : {
390 0 : if ( !IsCaseMap() && !IsKern() )
391 0 : return Size( pOut->GetTextWidth( rTxt ), pOut->GetTextHeight() );
392 :
393 0 : Size aTxtSize;
394 0 : aTxtSize.setHeight( pOut->GetTextHeight() );
395 0 : if ( !IsCaseMap() )
396 0 : aTxtSize.setWidth( pOut->GetTextWidth( rTxt ) );
397 : else
398 0 : aTxtSize.setWidth( pOut->GetTextWidth( CalcCaseMap( rTxt ) ) );
399 :
400 0 : if( IsKern() && ( rTxt.getLength() > 1 ) )
401 0 : aTxtSize.Width() += ( ( rTxt.getLength()-1 ) * long( nKern ) );
402 :
403 0 : return aTxtSize;
404 : }
405 :
406 0 : Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const OUString &rTxt,
407 : const sal_Int32 nIdx, const sal_Int32 nLen, sal_Int32* pDXArray ) const
408 : {
409 0 : if ( !IsCaseMap() && !IsKern() )
410 : return Size( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ),
411 0 : pOut->GetTextHeight() );
412 :
413 0 : Size aTxtSize;
414 0 : aTxtSize.setHeight( pOut->GetTextHeight() );
415 0 : if ( !IsCaseMap() )
416 0 : aTxtSize.setWidth( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ) );
417 : else
418 : aTxtSize.setWidth( pOut->GetTextArray( CalcCaseMap( rTxt ),
419 0 : pDXArray, nIdx, nLen ) );
420 :
421 0 : if( IsKern() && ( nLen > 1 ) )
422 : {
423 0 : aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) );
424 :
425 0 : if ( pDXArray )
426 : {
427 0 : for ( sal_Int32 i = 0; i < nLen; i++ )
428 0 : pDXArray[i] += ( (i+1) * long( nKern ) );
429 : // The last one is a nKern too big:
430 0 : pDXArray[nLen-1] -= nKern;
431 : }
432 : }
433 0 : return aTxtSize;
434 : }
435 :
436 :
437 0 : Size SvxFont::GetTxtSize( const OutputDevice *pOut, const OUString &rTxt,
438 : const sal_Int32 nIdx, const sal_Int32 nLen ) const
439 : {
440 0 : sal_Int32 nTmp = nLen;
441 0 : if ( nTmp == SAL_MAX_INT32 ) // already initialized?
442 0 : nTmp = rTxt.getLength();
443 0 : Font aOldFont( ChgPhysFont((OutputDevice *)pOut) );
444 0 : Size aTxtSize;
445 0 : if( IsCapital() && !rTxt.isEmpty() )
446 : {
447 0 : aTxtSize = GetCapitalSize( pOut, rTxt, nIdx, nTmp );
448 : }
449 0 : else aTxtSize = GetPhysTxtSize(pOut,rTxt,nIdx,nTmp);
450 0 : ((OutputDevice *)pOut)->SetFont( aOldFont );
451 0 : return aTxtSize;
452 : }
453 :
454 :
455 0 : void SvxFont::QuickDrawText( OutputDevice *pOut,
456 : const Point &rPos, const OUString &rTxt,
457 : const sal_Int32 nIdx, const sal_Int32 nLen, const sal_Int32* pDXArray ) const
458 : {
459 : // Font has to be selected in OutputDevice...
460 0 : if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() )
461 : {
462 0 : pOut->DrawTextArray( rPos, rTxt, pDXArray, nIdx, nLen );
463 0 : return;
464 : }
465 :
466 0 : Point aPos( rPos );
467 :
468 0 : if ( nEsc )
469 : {
470 0 : long nDiff = GetSize().Height();
471 0 : nDiff *= nEsc;
472 0 : nDiff /= 100;
473 :
474 0 : if ( !IsVertical() )
475 0 : aPos.Y() -= nDiff;
476 : else
477 0 : aPos.X() += nDiff;
478 : }
479 :
480 0 : if( IsCapital() )
481 : {
482 : DBG_ASSERT( !pDXArray, "DrawCapital not for TextArray!" );
483 0 : DrawCapital( pOut, aPos, rTxt, nIdx, nLen );
484 : }
485 : else
486 : {
487 0 : if ( IsKern() && !pDXArray )
488 : {
489 0 : Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen );
490 :
491 0 : if ( !IsCaseMap() )
492 0 : pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nLen );
493 : else
494 0 : pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nLen );
495 : }
496 : else
497 : {
498 0 : if ( !IsCaseMap() )
499 0 : pOut->DrawTextArray( aPos, rTxt, pDXArray, nIdx, nLen );
500 : else
501 0 : pOut->DrawTextArray( aPos, CalcCaseMap( rTxt ), pDXArray, nIdx, nLen );
502 : }
503 : }
504 : }
505 :
506 :
507 0 : void SvxFont::DrawPrev( OutputDevice *pOut, Printer* pPrinter,
508 : const Point &rPos, const OUString &rTxt,
509 : const sal_Int32 nIdx, const sal_Int32 nLen ) const
510 : {
511 0 : if ( !nLen || rTxt.isEmpty() )
512 0 : return;
513 0 : sal_Int32 nTmp = nLen;
514 :
515 0 : if ( nTmp == SAL_MAX_INT32 ) // already initialized?
516 0 : nTmp = rTxt.getLength();
517 0 : Point aPos( rPos );
518 :
519 0 : if ( nEsc )
520 : {
521 : short nTmpEsc;
522 0 : if( DFLT_ESC_AUTO_SUPER == nEsc )
523 0 : nTmpEsc = 33;
524 0 : else if( DFLT_ESC_AUTO_SUB == nEsc )
525 0 : nTmpEsc = -20;
526 : else
527 0 : nTmpEsc = nEsc;
528 0 : Size aSize = ( this->GetSize() );
529 0 : aPos.Y() -= ( ( nTmpEsc * long( aSize.Height() ) ) / 100L );
530 : }
531 0 : Font aOldFont( ChgPhysFont( pOut ) );
532 0 : Font aOldPrnFont( ChgPhysFont( pPrinter ) );
533 :
534 0 : if ( IsCapital() )
535 0 : DrawCapital( pOut, aPos, rTxt, nIdx, nTmp );
536 : else
537 : {
538 0 : Size aSize = GetPhysTxtSize( pPrinter, rTxt, nIdx, nTmp );
539 :
540 0 : if ( !IsCaseMap() )
541 0 : pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
542 : else
543 : {
544 : // #108210#
545 0 : const OUString aNewText = CalcCaseMap(rTxt);
546 0 : sal_Bool bCaseMapLengthDiffers(aNewText.getLength() != rTxt.getLength());
547 :
548 0 : if(bCaseMapLengthDiffers)
549 : {
550 : // If strings differ work preparing the necessary snippet to address that
551 : // potential difference
552 0 : const OUString aSnippet(rTxt.copy( nIdx, nTmp));
553 0 : OUString _aNewText = CalcCaseMap(aSnippet);
554 :
555 0 : pOut->DrawStretchText( aPos, aSize.Width(), _aNewText, 0, _aNewText.getLength() );
556 : }
557 : else
558 : {
559 0 : pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nTmp );
560 0 : }
561 : }
562 : }
563 0 : pOut->SetFont(aOldFont);
564 0 : pPrinter->SetFont( aOldPrnFont );
565 : }
566 :
567 :
568 0 : SvxFont& SvxFont::operator=( const Font& rFont )
569 : {
570 0 : Font::operator=( rFont );
571 0 : return *this;
572 : }
573 :
574 0 : SvxFont& SvxFont::operator=( const SvxFont& rFont )
575 : {
576 0 : Font::operator=( rFont );
577 0 : eCaseMap = rFont.eCaseMap;
578 0 : nEsc = rFont.nEsc;
579 0 : nPropr = rFont.nPropr;
580 0 : nKern = rFont.nKern;
581 0 : return *this;
582 : }
583 :
584 : class SvxDoGetCapitalSize : public SvxDoCapitals
585 : {
586 : protected:
587 : SvxFont* pFont;
588 : Size aTxtSize;
589 : short nKern;
590 : public:
591 0 : SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut,
592 : const OUString &_rTxt, const sal_Int32 _nIdx,
593 : const sal_Int32 _nLen, const short _nKrn )
594 : : SvxDoCapitals( (OutputDevice*)_pOut, _rTxt, _nIdx, _nLen ),
595 : pFont( _pFnt ),
596 0 : nKern( _nKrn )
597 0 : { }
598 :
599 0 : virtual ~SvxDoGetCapitalSize() {}
600 :
601 : virtual void Do( const OUString &rTxt, const sal_Int32 nIdx,
602 : const sal_Int32 nLen, const sal_Bool bUpper ) SAL_OVERRIDE;
603 :
604 0 : const Size &GetSize() const { return aTxtSize; };
605 : };
606 :
607 0 : void SvxDoGetCapitalSize::Do( const OUString &_rTxt, const sal_Int32 _nIdx,
608 : const sal_Int32 _nLen, const sal_Bool bUpper )
609 : {
610 0 : Size aPartSize;
611 0 : if ( !bUpper )
612 : {
613 0 : sal_uInt8 nProp = pFont->GetPropr();
614 0 : pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
615 0 : pFont->SetPhysFont( pOut );
616 0 : aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
617 0 : aPartSize.setHeight( pOut->GetTextHeight() );
618 0 : aTxtSize.Height() = aPartSize.Height();
619 0 : pFont->SetPropr( nProp );
620 0 : pFont->SetPhysFont( pOut );
621 : }
622 : else
623 : {
624 0 : aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
625 0 : aPartSize.setHeight( pOut->GetTextHeight() );
626 : }
627 0 : aTxtSize.Width() += aPartSize.Width();
628 0 : aTxtSize.Width() += ( _nLen * long( nKern ) );
629 0 : }
630 :
631 0 : Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt,
632 : const sal_Int32 nIdx, const sal_Int32 nLen) const
633 : {
634 : // Start:
635 0 : SvxDoGetCapitalSize aDo( (SvxFont *)this, pOut, rTxt, nIdx, nLen, nKern );
636 0 : DoOnCapitals( aDo );
637 0 : Size aTxtSize( aDo.GetSize() );
638 :
639 : // End:
640 0 : if( !aTxtSize.Height() )
641 : {
642 0 : aTxtSize.setWidth( 0 );
643 0 : aTxtSize.setHeight( pOut->GetTextHeight() );
644 : }
645 0 : return aTxtSize;
646 : }
647 :
648 0 : class SvxDoDrawCapital : public SvxDoCapitals
649 : {
650 : protected:
651 : SvxFont *pFont;
652 : Point aPos;
653 : Point aSpacePos;
654 : short nKern;
655 : public:
656 0 : SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const OUString &_rTxt,
657 : const sal_Int32 _nIdx, const sal_Int32 _nLen,
658 : const Point &rPos, const short nKrn )
659 : : SvxDoCapitals( _pOut, _rTxt, _nIdx, _nLen ),
660 : pFont( pFnt ),
661 : aPos( rPos ),
662 : aSpacePos( rPos ),
663 0 : nKern( nKrn )
664 0 : { }
665 : virtual void DoSpace( const sal_Bool bDraw ) SAL_OVERRIDE;
666 : virtual void SetSpace() SAL_OVERRIDE;
667 : virtual void Do( const OUString &rTxt, const sal_Int32 nIdx,
668 : const sal_Int32 nLen, const sal_Bool bUpper ) SAL_OVERRIDE;
669 : };
670 :
671 0 : void SvxDoDrawCapital::DoSpace( const sal_Bool bDraw )
672 : {
673 0 : if ( bDraw || pFont->IsWordLineMode() )
674 : {
675 0 : sal_uLong nDiff = (sal_uLong)(aPos.X() - aSpacePos.X());
676 0 : if ( nDiff )
677 : {
678 0 : sal_Bool bWordWise = pFont->IsWordLineMode();
679 0 : sal_Bool bTrans = pFont->IsTransparent();
680 0 : pFont->SetWordLineMode( false );
681 0 : pFont->SetTransparent( true );
682 0 : pFont->SetPhysFont( pOut );
683 0 : pOut->DrawStretchText( aSpacePos, nDiff, " ", 0, 2 );
684 0 : pFont->SetWordLineMode( bWordWise );
685 0 : pFont->SetTransparent( bTrans );
686 0 : pFont->SetPhysFont( pOut );
687 : }
688 : }
689 0 : }
690 :
691 0 : void SvxDoDrawCapital::SetSpace()
692 : {
693 0 : if ( pFont->IsWordLineMode() )
694 0 : aSpacePos.X() = aPos.X();
695 0 : }
696 :
697 0 : void SvxDoDrawCapital::Do( const OUString &_rTxt, const sal_Int32 _nIdx,
698 : const sal_Int32 _nLen, const sal_Bool bUpper)
699 : {
700 0 : sal_uInt8 nProp = 0;
701 0 : Size aPartSize;
702 :
703 : // Set the desired font
704 0 : FontUnderline eUnder = pFont->GetUnderline();
705 0 : FontStrikeout eStrike = pFont->GetStrikeout();
706 0 : pFont->SetUnderline( UNDERLINE_NONE );
707 0 : pFont->SetStrikeout( STRIKEOUT_NONE );
708 0 : if ( !bUpper )
709 : {
710 0 : nProp = pFont->GetPropr();
711 0 : pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
712 : }
713 0 : pFont->SetPhysFont( pOut );
714 :
715 0 : aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
716 0 : aPartSize.setHeight( pOut->GetTextHeight() );
717 0 : long nWidth = aPartSize.Width();
718 0 : if ( nKern )
719 : {
720 0 : aPos.X() += (nKern/2);
721 0 : if ( _nLen ) nWidth += (_nLen*long(nKern));
722 : }
723 0 : pOut->DrawStretchText(aPos,nWidth-nKern,_rTxt,_nIdx,_nLen);
724 :
725 : // Restore Font
726 0 : pFont->SetUnderline( eUnder );
727 0 : pFont->SetStrikeout( eStrike );
728 0 : if ( !bUpper )
729 0 : pFont->SetPropr( nProp );
730 0 : pFont->SetPhysFont( pOut );
731 :
732 0 : aPos.X() += nWidth-(nKern/2);
733 0 : }
734 :
735 : /*************************************************************************
736 : * SvxFont::DrawCapital() draws the uppercase letter.
737 : *************************************************************************/
738 :
739 0 : void SvxFont::DrawCapital( OutputDevice *pOut,
740 : const Point &rPos, const OUString &rTxt,
741 : const sal_Int32 nIdx, const sal_Int32 nLen ) const
742 : {
743 0 : SvxDoDrawCapital aDo( (SvxFont *)this,pOut,rTxt,nIdx,nLen,rPos,nKern );
744 0 : DoOnCapitals( aDo );
745 0 : }
746 :
747 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|