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