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 <vcl/metric.hxx>
21 #include <vcl/outdev.hxx>
22 #include <vcl/print.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/gen.hxx>
25 #include <tools/poly.hxx>
26 #include <unotools/charclass.hxx>
27 #include <com/sun/star/i18n/KCharacterType.hpp>
28 #include <editeng/svxfont.hxx>
29 #include <editeng/escapementitem.hxx>
30 #include <sal/log.hxx>
31
SvxFont()32 SvxFont::SvxFont()
33 {
34 nKern = nEsc = 0;
35 nPropr = 100;
36 eCaseMap = SvxCaseMap::NotMapped;
37 SetLanguage(LANGUAGE_SYSTEM);
38 }
39
SvxFont(const vcl::Font & rFont)40 SvxFont::SvxFont( const vcl::Font &rFont )
41 : Font( rFont )
42 {
43 nKern = nEsc = 0;
44 nPropr = 100;
45 eCaseMap = SvxCaseMap::NotMapped;
46 SetLanguage(LANGUAGE_SYSTEM);
47 }
48
SvxFont(const SvxFont & rFont)49 SvxFont::SvxFont( const SvxFont &rFont )
50 : Font( rFont )
51 {
52 nKern = rFont.GetFixKerning();
53 nEsc = rFont.GetEscapement();
54 nPropr = rFont.GetPropr();
55 eCaseMap = rFont.GetCaseMap();
56 SetLanguage(rFont.GetLanguage());
57 }
58
SetNonAutoEscapement(short nNewEsc,const OutputDevice * pOutDev)59 void SvxFont::SetNonAutoEscapement(short nNewEsc, const OutputDevice* pOutDev)
60 {
61 nEsc = nNewEsc;
62 if ( abs(nEsc) == DFLT_ESC_AUTO_SUPER )
63 {
64 double fAutoAscent = .8;
65 double fAutoDescent = .2;
66 if ( pOutDev )
67 {
68 const FontMetric& rFontMetric = pOutDev->GetFontMetric();
69 double fFontHeight = rFontMetric.GetAscent() + rFontMetric.GetDescent();
70 if ( fFontHeight )
71 {
72 fAutoAscent = rFontMetric.GetAscent() / fFontHeight;
73 fAutoDescent = rFontMetric.GetDescent() / fFontHeight;
74 }
75 }
76
77 if ( nEsc == DFLT_ESC_AUTO_SUPER )
78 nEsc = fAutoAscent * (100 - nPropr);
79 else //DFLT_ESC_AUTO_SUB
80 nEsc = fAutoDescent * -(100 - nPropr);
81 }
82
83 if ( nEsc > MAX_ESC_POS )
84 nEsc = MAX_ESC_POS;
85 else if ( nEsc < -MAX_ESC_POS )
86 nEsc = -MAX_ESC_POS;
87 }
88
DrawArrow(OutputDevice & rOut,const tools::Rectangle & rRect,const Size & rSize,const Color & rCol,bool bLeftOrTop,bool bVertical)89 tools::Polygon SvxFont::DrawArrow( OutputDevice &rOut, const tools::Rectangle& rRect,
90 const Size& rSize, const Color& rCol, bool bLeftOrTop, bool bVertical )
91 {
92 tools::Polygon aPoly;
93 Point aTmp;
94 Point aNxt;
95 if (bVertical)
96 {
97 tools::Long nLeft = ((rRect.Left() + rRect.Right()) / 2) - (rSize.Height() / 2);
98 tools::Long nRight = ((rRect.Left() + rRect.Right()) / 2) + (rSize.Height() / 2);
99 tools::Long nMid = (rRect.Left() + rRect.Right()) / 2;
100 tools::Long nTop = ((rRect.Top() + rRect.Bottom()) / 2) - (rSize.Height() / 2);
101 tools::Long nBottom = nTop + rSize.Height();
102 if (nTop < rRect.Top())
103 {
104 if (bLeftOrTop)
105 {
106 nTop = rRect.Top();
107 nBottom = rRect.Bottom();
108 }
109 else
110 {
111 nTop = rRect.Bottom();
112 nBottom = rRect.Bottom() - (rSize.Height() / 2);
113 }
114 }
115 aTmp.setX(nRight);
116 aTmp.setY(nBottom);
117 aNxt.setX(nMid);
118 aNxt.setY(nTop);
119 aPoly.Insert(0, aTmp);
120 aPoly.Insert(0, aNxt);
121 aTmp.setX(nLeft);
122 aPoly.Insert(0, aTmp);
123 }
124 else
125 {
126 tools::Long nLeft = (rRect.Left() + rRect.Right() - rSize.Width()) / 2;
127 tools::Long nRight = nLeft + rSize.Width();
128 tools::Long nMid = (rRect.Top() + rRect.Bottom()) / 2;
129 tools::Long nTop = nMid - rSize.Height() / 2;
130 tools::Long nBottom = nTop + rSize.Height();
131 if (nLeft < rRect.Left())
132 {
133 nLeft = rRect.Left();
134 nRight = rRect.Right();
135 }
136 aTmp.setX(bLeftOrTop ? nLeft : nRight);
137 aTmp.setY(nMid);
138 aNxt.setX(bLeftOrTop ? nRight : nLeft);
139 aNxt.setY(nTop);
140 aPoly.Insert(0, aTmp);
141 aPoly.Insert(0, aNxt);
142 aNxt.setY(nBottom);
143 aPoly.Insert(0, aNxt);
144 }
145 Color aOldLineColor = rOut.GetLineColor();
146 Color aOldFillColor = rOut.GetFillColor();
147 rOut.SetFillColor( rCol );
148 rOut.SetLineColor( COL_BLACK );
149 rOut.DrawPolygon( aPoly );
150 rOut.DrawLine( aTmp, aNxt );
151 rOut.SetLineColor( aOldLineColor );
152 rOut.SetFillColor( aOldFillColor );
153 return aPoly;
154 }
155
CalcCaseMap(const OUString & rTxt) const156 OUString SvxFont::CalcCaseMap(const OUString &rTxt) const
157 {
158 if (!IsCaseMap() || rTxt.isEmpty())
159 return rTxt;
160 OUString aTxt(rTxt);
161 // I still have to get the language
162 const LanguageType eLang = LANGUAGE_DONTKNOW == GetLanguage()
163 ? LANGUAGE_SYSTEM : GetLanguage();
164
165 LanguageTag aLanguageTag(eLang);
166 CharClass aCharClass( aLanguageTag );
167
168 switch( eCaseMap )
169 {
170 case SvxCaseMap::SmallCaps:
171 case SvxCaseMap::Uppercase:
172 {
173 aTxt = aCharClass.uppercase( aTxt );
174 break;
175 }
176
177 case SvxCaseMap::Lowercase:
178 {
179 aTxt = aCharClass.lowercase( aTxt );
180 break;
181 }
182 case SvxCaseMap::Capitalize:
183 {
184 // Every beginning of a word is capitalized, the rest of the word
185 // is taken over as is.
186 // Bug: if the attribute starts in the middle of the word.
187 bool bBlank = true;
188
189 for (sal_Int32 i = 0; i < aTxt.getLength(); ++i)
190 {
191 if( aTxt[i] == ' ' || aTxt[i] == '\t')
192 bBlank = true;
193 else
194 {
195 if (bBlank)
196 {
197 OUString sTitle(aCharClass.uppercase(OUString(aTxt[i])));
198 aTxt = aTxt.replaceAt(i, 1, sTitle);
199 }
200 bBlank = false;
201 }
202 }
203 break;
204 }
205 default:
206 {
207 SAL_WARN( "editeng", "SvxFont::CaseMapTxt: unknown casemap");
208 break;
209 }
210 }
211 return aTxt;
212 }
213
214 /*************************************************************************
215 * class SvxDoCapitals
216 * The virtual Method Do si called by SvxFont::DoOnCapitals alternately
217 * the uppercase and lowercase parts. The derivate of SvxDoCapitals fills
218 * this method with life.
219 *************************************************************************/
220
221 class SvxDoCapitals
222 {
223 protected:
224 VclPtr<OutputDevice> pOut;
225 const OUString &rTxt;
226 const sal_Int32 nIdx;
227 const sal_Int32 nLen;
228
229 public:
SvxDoCapitals(OutputDevice * _pOut,const OUString & _rTxt,const sal_Int32 _nIdx,const sal_Int32 _nLen)230 SvxDoCapitals( OutputDevice *_pOut, const OUString &_rTxt,
231 const sal_Int32 _nIdx, const sal_Int32 _nLen )
232 : pOut(_pOut), rTxt(_rTxt), nIdx(_nIdx), nLen(_nLen)
233 { }
234
~SvxDoCapitals()235 virtual ~SvxDoCapitals() {}
236
237 virtual void DoSpace( const bool bDraw );
238 virtual void SetSpace();
239 virtual void Do( const OUString &rTxt,
240 const sal_Int32 nIdx, const sal_Int32 nLen,
241 const bool bUpper ) = 0;
242
GetTxt() const243 const OUString &GetTxt() const { return rTxt; }
GetIdx() const244 sal_Int32 GetIdx() const { return nIdx; }
GetLen() const245 sal_Int32 GetLen() const { return nLen; }
246 };
247
DoSpace(const bool)248 void SvxDoCapitals::DoSpace( const bool /*bDraw*/ ) { }
249
SetSpace()250 void SvxDoCapitals::SetSpace() { }
251
252 /*************************************************************************
253 * SvxFont::DoOnCapitals() const
254 * Decomposes the String into uppercase and lowercase letters and then
255 * calls the method SvxDoCapitals::Do( ).
256 *************************************************************************/
257
DoOnCapitals(SvxDoCapitals & rDo) const258 void SvxFont::DoOnCapitals(SvxDoCapitals &rDo) const
259 {
260 const OUString &rTxt = rDo.GetTxt();
261 const sal_Int32 nIdx = rDo.GetIdx();
262 const sal_Int32 nLen = rDo.GetLen();
263
264 const OUString aTxt( CalcCaseMap( rTxt ) );
265 const sal_Int32 nTxtLen = std::min( rTxt.getLength(), nLen );
266 sal_Int32 nPos = 0;
267 sal_Int32 nOldPos = nPos;
268
269 // Test if string length differ between original and CaseMapped
270 bool bCaseMapLengthDiffers(aTxt.getLength() != rTxt.getLength());
271
272 const LanguageType eLang = LANGUAGE_DONTKNOW == GetLanguage()
273 ? LANGUAGE_SYSTEM : GetLanguage();
274
275 LanguageTag aLanguageTag(eLang);
276 CharClass aCharClass( aLanguageTag );
277 OUString aCharString;
278
279 while( nPos < nTxtLen )
280 {
281 // first in turn are the uppercase letters
282
283 // There are characters that are both upper- and lower-case L (eg blank)
284 // Such ambiguities lead to chaos, this is why these characters are
285 // allocated to the lowercase characters!
286
287 while( nPos < nTxtLen )
288 {
289 aCharString = rTxt.copy( nPos + nIdx, 1 );
290 sal_Int32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
291 if ( nCharacterType & css::i18n::KCharacterType::LOWER )
292 break;
293 if ( ! ( nCharacterType & css::i18n::KCharacterType::UPPER ) )
294 break;
295 ++nPos;
296 }
297 if( nOldPos != nPos )
298 {
299 if(bCaseMapLengthDiffers)
300 {
301 // If strings differ work preparing the necessary snippet to address that
302 // potential difference
303 const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos-nOldPos);
304 OUString aNewText = CalcCaseMap(aSnippet);
305
306 rDo.Do( aNewText, 0, aNewText.getLength(), true );
307 }
308 else
309 {
310 rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, true );
311 }
312
313 nOldPos = nPos;
314 }
315 // Now the lowercase are processed (without blanks)
316 while( nPos < nTxtLen )
317 {
318 sal_uInt32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
319 if ( nCharacterType & css::i18n::KCharacterType::UPPER )
320 break;
321 if ( aCharString == " " )
322 break;
323 if( ++nPos < nTxtLen )
324 aCharString = rTxt.copy( nPos + nIdx, 1 );
325 }
326 if( nOldPos != nPos )
327 {
328 if(bCaseMapLengthDiffers)
329 {
330 // If strings differ work preparing the necessary snippet to address that
331 // potential difference
332 const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos - nOldPos);
333 OUString aNewText = CalcCaseMap(aSnippet);
334
335 rDo.Do( aNewText, 0, aNewText.getLength(), false );
336 }
337 else
338 {
339 rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, false );
340 }
341
342 nOldPos = nPos;
343 }
344 // Now the blanks are<processed
345 while( nPos < nTxtLen && aCharString == " " && ++nPos < nTxtLen )
346 aCharString = rTxt.copy( nPos + nIdx, 1 );
347
348 if( nOldPos != nPos )
349 {
350 rDo.DoSpace( false );
351
352 if(bCaseMapLengthDiffers)
353 {
354 // If strings differ work preparing the necessary snippet to address that
355 // potential difference
356 const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos - nOldPos);
357 OUString aNewText = CalcCaseMap(aSnippet);
358
359 rDo.Do( aNewText, 0, aNewText.getLength(), false );
360 }
361 else
362 {
363 rDo.Do( aTxt, nIdx + nOldPos, nPos - nOldPos, false );
364 }
365
366 nOldPos = nPos;
367 rDo.SetSpace();
368 }
369 }
370 rDo.DoSpace( true );
371 }
372
373
SetPhysFont(OutputDevice & rOut) const374 void SvxFont::SetPhysFont(OutputDevice& rOut) const
375 {
376 const vcl::Font& rCurrentFont = rOut.GetFont();
377 if ( nPropr == 100 )
378 {
379 if ( !rCurrentFont.IsSameInstance( *this ) )
380 rOut.SetFont( *this );
381 }
382 else
383 {
384 Font aNewFont( *this );
385 Size aSize( aNewFont.GetFontSize() );
386 aNewFont.SetFontSize( Size( aSize.Width() * nPropr / 100,
387 aSize.Height() * nPropr / 100 ) );
388 if ( !rCurrentFont.IsSameInstance( aNewFont ) )
389 rOut.SetFont( aNewFont );
390 }
391 }
392
ChgPhysFont(OutputDevice & rOut) const393 vcl::Font SvxFont::ChgPhysFont(OutputDevice& rOut) const
394 {
395 vcl::Font aOldFont(rOut.GetFont());
396 SetPhysFont(rOut);
397 return aOldFont;
398 }
399
GetPhysTxtSize(const OutputDevice * pOut,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen) const400 Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const OUString &rTxt,
401 const sal_Int32 nIdx, const sal_Int32 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 const OUString aNewText = CalcCaseMap(rTxt);
414 bool bCaseMapLengthDiffers(aNewText.getLength() != rTxt.getLength());
415 sal_Int32 nWidth(0);
416
417 if(bCaseMapLengthDiffers)
418 {
419 // If strings differ work preparing the necessary snippet to address that
420 // potential difference
421 const OUString aSnippet = rTxt.copy(nIdx, nLen);
422 OUString _aNewText = CalcCaseMap(aSnippet);
423 nWidth = pOut->GetTextWidth( _aNewText, 0, _aNewText.getLength() );
424 }
425 else
426 {
427 nWidth = pOut->GetTextWidth( aNewText, nIdx, nLen );
428 }
429
430 aTxtSize.setWidth(nWidth);
431 }
432
433 if( IsKern() && ( nLen > 1 ) )
434 aTxtSize.AdjustWidth( ( nLen-1 ) * tools::Long( nKern ) );
435
436 return aTxtSize;
437 }
438
GetPhysTxtSize(const OutputDevice * pOut)439 Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut )
440 {
441 if ( !IsCaseMap() && !IsKern() )
442 return Size( pOut->GetTextWidth( "" ), pOut->GetTextHeight() );
443
444 Size aTxtSize;
445 aTxtSize.setHeight( pOut->GetTextHeight() );
446 if ( !IsCaseMap() )
447 aTxtSize.setWidth( pOut->GetTextWidth( "" ) );
448 else
449 aTxtSize.setWidth( pOut->GetTextWidth( CalcCaseMap( "" ) ) );
450
451 return aTxtSize;
452 }
453
QuickGetTextSize(const OutputDevice * pOut,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen,tools::Long * pDXArray) const454 Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const OUString &rTxt,
455 const sal_Int32 nIdx, const sal_Int32 nLen, tools::Long* pDXArray ) const
456 {
457 if ( !IsCaseMap() && !IsKern() )
458 return Size( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ),
459 pOut->GetTextHeight() );
460
461 Size aTxtSize;
462 aTxtSize.setHeight( pOut->GetTextHeight() );
463 if ( !IsCaseMap() )
464 aTxtSize.setWidth( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ) );
465 else
466 aTxtSize.setWidth( pOut->GetTextArray( CalcCaseMap( rTxt ),
467 pDXArray, nIdx, nLen ) );
468
469 if( IsKern() && ( nLen > 1 ) )
470 {
471 aTxtSize.AdjustWidth( ( nLen-1 ) * tools::Long( nKern ) );
472
473 if ( pDXArray )
474 {
475 for ( sal_Int32 i = 0; i < nLen; i++ )
476 pDXArray[i] += ( (i+1) * tools::Long( nKern ) );
477 // The last one is a nKern too big:
478 pDXArray[nLen-1] -= nKern;
479 }
480 }
481 return aTxtSize;
482 }
483
GetTextSize(const OutputDevice & rOut,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen) const484 Size SvxFont::GetTextSize(const OutputDevice& rOut, const OUString &rTxt,
485 const sal_Int32 nIdx, const sal_Int32 nLen) const
486 {
487 sal_Int32 nTmp = nLen;
488 if ( nTmp == SAL_MAX_INT32 ) // already initialized?
489 nTmp = rTxt.getLength();
490 Font aOldFont( ChgPhysFont(const_cast<OutputDevice&>(rOut)));
491 Size aTxtSize;
492 if( IsCapital() && !rTxt.isEmpty() )
493 {
494 aTxtSize = GetCapitalSize(&rOut, rTxt, nIdx, nTmp);
495 }
496 else aTxtSize = GetPhysTxtSize(&rOut,rTxt,nIdx,nTmp);
497 const_cast<OutputDevice&>(rOut).SetFont(aOldFont);
498 return aTxtSize;
499 }
500
QuickDrawText(OutputDevice * pOut,const Point & rPos,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen,const tools::Long * pDXArray) const501 void SvxFont::QuickDrawText( OutputDevice *pOut,
502 const Point &rPos, const OUString &rTxt,
503 const sal_Int32 nIdx, const sal_Int32 nLen, const tools::Long* pDXArray ) const
504 {
505
506 // Font has to be selected in OutputDevice...
507 if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() )
508 {
509 pOut->DrawTextArray( rPos, rTxt, pDXArray, nIdx, nLen );
510 return;
511 }
512
513 Point aPos( rPos );
514
515 if ( nEsc )
516 {
517 tools::Long nDiff = GetFontSize().Height();
518 nDiff *= nEsc;
519 nDiff /= 100;
520
521 if ( !IsVertical() )
522 aPos.AdjustY( -nDiff );
523 else
524 aPos.AdjustX(nDiff );
525 }
526
527 if( IsCapital() )
528 {
529 DBG_ASSERT( !pDXArray, "DrawCapital not for TextArray!" );
530 DrawCapital( pOut, aPos, rTxt, nIdx, nLen );
531 }
532 else
533 {
534 if ( IsKern() && !pDXArray )
535 {
536 Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen );
537
538 if ( !IsCaseMap() )
539 pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nLen );
540 else
541 pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nLen );
542 }
543 else
544 {
545 if ( !IsCaseMap() )
546 pOut->DrawTextArray( aPos, rTxt, pDXArray, nIdx, nLen );
547 else
548 pOut->DrawTextArray( aPos, CalcCaseMap( rTxt ), pDXArray, nIdx, nLen );
549 }
550 }
551 }
552
553
DrawPrev(OutputDevice * pOut,Printer * pPrinter,const Point & rPos,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen) const554 void SvxFont::DrawPrev( OutputDevice *pOut, Printer* pPrinter,
555 const Point &rPos, const OUString &rTxt,
556 const sal_Int32 nIdx, const sal_Int32 nLen ) const
557 {
558 if ( !nLen || rTxt.isEmpty() )
559 return;
560 sal_Int32 nTmp = nLen;
561
562 if ( nTmp == SAL_MAX_INT32 ) // already initialized?
563 nTmp = rTxt.getLength();
564 Point aPos( rPos );
565
566 if ( nEsc )
567 {
568 short nTmpEsc;
569 if( DFLT_ESC_AUTO_SUPER == nEsc )
570 {
571 nTmpEsc = .8 * (100 - nPropr);
572 assert (nTmpEsc == DFLT_ESC_SUPER && "I'm sure this formula needs to be changed, but how to confirm that???");
573 nTmpEsc = DFLT_ESC_SUPER;
574 }
575 else if( DFLT_ESC_AUTO_SUB == nEsc )
576 {
577 nTmpEsc = .2 * -(100 - nPropr);
578 assert (nTmpEsc == -20 && "I'm sure this formula needs to be changed, but how to confirm that???");
579 nTmpEsc = -20;
580 }
581 else
582 nTmpEsc = nEsc;
583 Size aSize = GetFontSize();
584 aPos.AdjustY( -(( nTmpEsc * aSize.Height() ) / 100) );
585 }
586 Font aOldFont( ChgPhysFont(*pOut) );
587 Font aOldPrnFont( ChgPhysFont(*pPrinter) );
588
589 if ( IsCapital() )
590 DrawCapital( pOut, aPos, rTxt, nIdx, nTmp );
591 else
592 {
593 Size aSize = GetPhysTxtSize( pPrinter, rTxt, nIdx, nTmp );
594
595 if ( !IsCaseMap() )
596 pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
597 else
598 {
599 const OUString aNewText = CalcCaseMap(rTxt);
600 bool bCaseMapLengthDiffers(aNewText.getLength() != rTxt.getLength());
601
602 if(bCaseMapLengthDiffers)
603 {
604 // If strings differ work preparing the necessary snippet to address that
605 // potential difference
606 const OUString aSnippet(rTxt.copy( nIdx, nTmp));
607 OUString _aNewText = CalcCaseMap(aSnippet);
608
609 pOut->DrawStretchText( aPos, aSize.Width(), _aNewText, 0, _aNewText.getLength() );
610 }
611 else
612 {
613 pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nTmp );
614 }
615 }
616 }
617 pOut->SetFont(aOldFont);
618 pPrinter->SetFont( aOldPrnFont );
619 }
620
621
operator =(const vcl::Font & rFont)622 SvxFont& SvxFont::operator=( const vcl::Font& rFont )
623 {
624 Font::operator=( rFont );
625 return *this;
626 }
627
operator =(const SvxFont & rFont)628 SvxFont& SvxFont::operator=( const SvxFont& rFont )
629 {
630 Font::operator=( rFont );
631 eCaseMap = rFont.eCaseMap;
632 nEsc = rFont.nEsc;
633 nPropr = rFont.nPropr;
634 nKern = rFont.nKern;
635 return *this;
636 }
637
638 namespace {
639
640 class SvxDoGetCapitalSize : public SvxDoCapitals
641 {
642 protected:
643 SvxFont* pFont;
644 Size aTxtSize;
645 short nKern;
646 public:
SvxDoGetCapitalSize(SvxFont * _pFnt,const OutputDevice * _pOut,const OUString & _rTxt,const sal_Int32 _nIdx,const sal_Int32 _nLen,const short _nKrn)647 SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut,
648 const OUString &_rTxt, const sal_Int32 _nIdx,
649 const sal_Int32 _nLen, const short _nKrn )
650 : SvxDoCapitals( const_cast<OutputDevice*>(_pOut), _rTxt, _nIdx, _nLen ),
651 pFont( _pFnt ),
652 nKern( _nKrn )
653 { }
654
655 virtual void Do( const OUString &rTxt, const sal_Int32 nIdx,
656 const sal_Int32 nLen, const bool bUpper ) override;
657
GetSize() const658 const Size &GetSize() const { return aTxtSize; };
659 };
660
661 }
662
Do(const OUString & _rTxt,const sal_Int32 _nIdx,const sal_Int32 _nLen,const bool bUpper)663 void SvxDoGetCapitalSize::Do( const OUString &_rTxt, const sal_Int32 _nIdx,
664 const sal_Int32 _nLen, const bool bUpper )
665 {
666 Size aPartSize;
667 if ( !bUpper )
668 {
669 sal_uInt8 nProp = pFont->GetPropr();
670 pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
671 pFont->SetPhysFont( *pOut );
672 aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
673 aPartSize.setHeight( pOut->GetTextHeight() );
674 aTxtSize.setHeight( aPartSize.Height() );
675 pFont->SetPropr( nProp );
676 pFont->SetPhysFont( *pOut );
677 }
678 else
679 {
680 aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
681 aPartSize.setHeight( pOut->GetTextHeight() );
682 }
683 aTxtSize.AdjustWidth(aPartSize.Width() );
684 aTxtSize.AdjustWidth( _nLen * tools::Long( nKern ) );
685 }
686
GetCapitalSize(const OutputDevice * pOut,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen) const687 Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt,
688 const sal_Int32 nIdx, const sal_Int32 nLen) const
689 {
690 // Start:
691 SvxDoGetCapitalSize aDo( const_cast<SvxFont *>(this), pOut, rTxt, nIdx, nLen, nKern );
692 DoOnCapitals( aDo );
693 Size aTxtSize( aDo.GetSize() );
694
695 // End:
696 if( !aTxtSize.Height() )
697 {
698 aTxtSize.setWidth( 0 );
699 aTxtSize.setHeight( pOut->GetTextHeight() );
700 }
701 return aTxtSize;
702 }
703
704 namespace {
705
706 class SvxDoDrawCapital : public SvxDoCapitals
707 {
708 protected:
709 SvxFont *pFont;
710 Point aPos;
711 Point aSpacePos;
712 short nKern;
713 public:
SvxDoDrawCapital(SvxFont * pFnt,OutputDevice * _pOut,const OUString & _rTxt,const sal_Int32 _nIdx,const sal_Int32 _nLen,const Point & rPos,const short nKrn)714 SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const OUString &_rTxt,
715 const sal_Int32 _nIdx, const sal_Int32 _nLen,
716 const Point &rPos, const short nKrn )
717 : SvxDoCapitals( _pOut, _rTxt, _nIdx, _nLen ),
718 pFont( pFnt ),
719 aPos( rPos ),
720 aSpacePos( rPos ),
721 nKern( nKrn )
722 { }
723 virtual void DoSpace( const bool bDraw ) override;
724 virtual void SetSpace() override;
725 virtual void Do( const OUString &rTxt, const sal_Int32 nIdx,
726 const sal_Int32 nLen, const bool bUpper ) override;
727 };
728
729 }
730
DoSpace(const bool bDraw)731 void SvxDoDrawCapital::DoSpace( const bool bDraw )
732 {
733 if ( !(bDraw || pFont->IsWordLineMode()) )
734 return;
735
736 sal_uLong nDiff = static_cast<sal_uLong>(aPos.X() - aSpacePos.X());
737 if ( nDiff )
738 {
739 bool bWordWise = pFont->IsWordLineMode();
740 bool bTrans = pFont->IsTransparent();
741 pFont->SetWordLineMode( false );
742 pFont->SetTransparent( true );
743 pFont->SetPhysFont(*pOut);
744 pOut->DrawStretchText( aSpacePos, nDiff, " ", 0, 2 );
745 pFont->SetWordLineMode( bWordWise );
746 pFont->SetTransparent( bTrans );
747 pFont->SetPhysFont(*pOut);
748 }
749 }
750
SetSpace()751 void SvxDoDrawCapital::SetSpace()
752 {
753 if ( pFont->IsWordLineMode() )
754 aSpacePos.setX( aPos.X() );
755 }
756
Do(const OUString & _rTxt,const sal_Int32 _nIdx,const sal_Int32 _nLen,const bool bUpper)757 void SvxDoDrawCapital::Do( const OUString &_rTxt, const sal_Int32 _nIdx,
758 const sal_Int32 _nLen, const bool bUpper)
759 {
760 sal_uInt8 nProp = 0;
761 Size aPartSize;
762
763 // Set the desired font
764 FontLineStyle eUnder = pFont->GetUnderline();
765 FontStrikeout eStrike = pFont->GetStrikeout();
766 pFont->SetUnderline( LINESTYLE_NONE );
767 pFont->SetStrikeout( STRIKEOUT_NONE );
768 if ( !bUpper )
769 {
770 nProp = pFont->GetPropr();
771 pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
772 }
773 pFont->SetPhysFont(*pOut);
774
775 aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
776 aPartSize.setHeight( pOut->GetTextHeight() );
777 tools::Long nWidth = aPartSize.Width();
778 if ( nKern )
779 {
780 aPos.AdjustX(nKern/2);
781 if ( _nLen ) nWidth += (_nLen*tools::Long(nKern));
782 }
783 pOut->DrawStretchText(aPos,nWidth-nKern,_rTxt,_nIdx,_nLen);
784
785 // Restore Font
786 pFont->SetUnderline( eUnder );
787 pFont->SetStrikeout( eStrike );
788 if ( !bUpper )
789 pFont->SetPropr( nProp );
790 pFont->SetPhysFont(*pOut);
791
792 aPos.AdjustX(nWidth-(nKern/2) );
793 }
794
795 /*************************************************************************
796 * SvxFont::DrawCapital() draws the uppercase letter.
797 *************************************************************************/
798
DrawCapital(OutputDevice * pOut,const Point & rPos,const OUString & rTxt,const sal_Int32 nIdx,const sal_Int32 nLen) const799 void SvxFont::DrawCapital( OutputDevice *pOut,
800 const Point &rPos, const OUString &rTxt,
801 const sal_Int32 nIdx, const sal_Int32 nLen ) const
802 {
803 SvxDoDrawCapital aDo( const_cast<SvxFont *>(this),pOut,rTxt,nIdx,nLen,rPos,nKern );
804 DoOnCapitals( aDo );
805 }
806
807 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
808