LibreOffice Module vcl (master) 1
text.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 <sal/config.h>
21
22#include <memory>
24
25#include <com/sun/star/i18n/WordType.hpp>
26#include <com/sun/star/i18n/XBreakIterator.hpp>
27#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
28
30#include <osl/file.h>
31#include <rtl/ustrbuf.hxx>
32#include <sal/log.hxx>
33#include <tools/lineend.hxx>
34#include <tools/debug.hxx>
36#include <vcl/ctrl.hxx>
37#include <vcl/gdimtf.hxx>
38#include <vcl/metaact.hxx>
39#include <vcl/metric.hxx>
40#include <vcl/mnemonic.hxx>
41#include <vcl/textrectinfo.hxx>
42#include <vcl/virdev.hxx>
43#include <vcl/sysdata.hxx>
44#include <vcl/unohelp.hxx>
45
46#include <ImplLayoutArgs.hxx>
47#include <ImplOutDevData.hxx>
48#include <drawmode.hxx>
49#include <salgdi.hxx>
50#include <svdata.hxx>
51#include <textlayout.hxx>
52#include <textlineinfo.hxx>
53#include <impglyphitem.hxx>
54#include <optional>
55#include <TextLayoutCache.hxx>
57
58#define TEXT_DRAW_ELLIPSIS (DrawTextFlags::EndEllipsis | DrawTextFlags::PathEllipsis | DrawTextFlags::NewsEllipsis)
59
61{
62 if( mpMetaFile )
63 mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
64
65 mnTextLayoutMode = nTextLayoutMode;
66
67 if( mpAlphaVDev )
68 mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
69}
70
72{
73 if( mpMetaFile )
74 mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
75
76 meTextLanguage = eTextLanguage;
77
78 if( mpAlphaVDev )
79 mpAlphaVDev->SetDigitLanguage( eTextLanguage );
80}
81
83{
84}
85
87{
88}
89
91{
92 mvLines.push_back(rLine);
93}
94
96{
97 mvLines.clear();
98}
99
101{
103
104 if ( mbInitTextColor )
105 {
107 mbInitTextColor = false;
108 }
109}
110
112 tools::Long nDistX, tools::Long nDistY, tools::Long nWidth, tools::Long nHeight )
113{
114 tools::Long nX = nDistX;
115 tools::Long nY = nDistY;
116
117 Degree10 nOrientation = mpFontInstance->mnOrientation;
118 if ( nOrientation )
119 {
120 // Rotate rect without rounding problems for 90 degree rotations
121 if ( !(nOrientation % 900_deg10) )
122 {
123 if ( nOrientation == 900_deg10 )
124 {
125 tools::Long nTemp = nX;
126 nX = nY;
127 nY = -nTemp;
128 nTemp = nWidth;
129 nWidth = nHeight;
130 nHeight = nTemp;
131 nY -= nHeight;
132 }
133 else if ( nOrientation == 1800_deg10 )
134 {
135 nX = -nX;
136 nY = -nY;
137 nX -= nWidth;
138 nY -= nHeight;
139 }
140 else /* ( nOrientation == 2700 ) */
141 {
142 tools::Long nTemp = nX;
143 nX = -nY;
144 nY = nTemp;
145 nTemp = nWidth;
146 nWidth = nHeight;
147 nHeight = nTemp;
148 nX -= nWidth;
149 }
150 }
151 else
152 {
153 nX += nBaseX;
154 nY += nBaseY;
155 // inflate because polygons are drawn smaller
156 tools::Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
157 tools::Polygon aPoly( aRect );
158 aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontInstance->mnOrientation );
159 ImplDrawPolygon( aPoly );
160 return;
161 }
162 }
163
164 nX += nBaseX;
165 nY += nBaseY;
166 mpGraphics->DrawRect( nX, nY, nWidth, nHeight, *this ); // original code
167
168}
169
171{
172 const tools::Long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
173 const DevicePoint aBase = rSalLayout.DrawBase();
174 const tools::Long nX = aBase.getX();
175 const tools::Long nY = aBase.getY();
176
178 {
180 mbInitLineColor = true;
181 }
183 mbInitFillColor = true;
184
185 ImplDrawTextRect( nX, nY, 0, -(mpFontInstance->mxFontMetric->GetAscent() + mnEmphasisAscent),
186 nWidth,
188}
189
191{
192 DevicePoint aPoint = rSalLayout.GetDrawPosition();
193 tools::Long nX = aPoint.getX();
194 tools::Long nY = aPoint.getY();
195
196 tools::Long nWidth = rSalLayout.GetTextWidth();
198
199 nY -= mpFontInstance->mxFontMetric->GetAscent() + mnEmphasisAscent;
200
201 if ( mpFontInstance->mnOrientation )
202 {
203 tools::Long nBaseX = nX, nBaseY = nY;
204 if ( !(mpFontInstance->mnOrientation % 900_deg10) )
205 {
206 tools::Long nX2 = nX+nWidth;
207 tools::Long nY2 = nY+nHeight;
208
209 Point aBasePt( nBaseX, nBaseY );
210 aBasePt.RotateAround( nX, nY, mpFontInstance->mnOrientation );
211 aBasePt.RotateAround( nX2, nY2, mpFontInstance->mnOrientation );
212 nWidth = nX2-nX;
213 nHeight = nY2-nY;
214 }
215 else
216 {
217 // inflate by +1+1 because polygons are drawn smaller
218 tools::Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
219 tools::Polygon aPoly( aRect );
220 aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontInstance->mnOrientation );
221 return aPoly.GetBoundRect();
222 }
223 }
224
225 return tools::Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
226}
227
229{
230 tools::Long nX = rSalLayout.DrawBase().getX();
231 tools::Long nY = rSalLayout.DrawBase().getY();
232
233 tools::Rectangle aBoundRect;
234 rSalLayout.DrawBase() = DevicePoint( 0, 0 );
235 rSalLayout.DrawOffset() = Point( 0, 0 );
236 if (!rSalLayout.GetBoundRect(aBoundRect))
237 {
238 // guess vertical text extents if GetBoundRect failed
239 tools::Long nRight = rSalLayout.GetTextWidth();
240 tools::Long nTop = mpFontInstance->mxFontMetric->GetAscent() + mnEmphasisAscent;
242 aBoundRect = tools::Rectangle( 0, -nTop, nRight, nHeight - nTop );
243 }
244
245 // cache virtual device for rotation
246 if (!mpOutDevData->mpRotateDev)
247 mpOutDevData->mpRotateDev = VclPtr<VirtualDevice>::Create(*this);
248 VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
249
250 // size it accordingly
251 if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
252 return false;
253
254 const vcl::font::FontSelectPattern& rPattern = mpFontInstance->GetFontSelectPattern();
255 vcl::Font aFont( GetFont() );
256 aFont.SetOrientation( 0_deg10 );
257 aFont.SetFontSize( Size( rPattern.mnWidth, rPattern.mnHeight ) );
258 pVDev->SetFont( aFont );
259 pVDev->SetTextColor( COL_BLACK );
260 pVDev->SetTextFillColor();
261 if (!pVDev->InitFont())
262 return false;
263 pVDev->ImplInitTextColor();
264
265 // draw text into upper left corner
266 rSalLayout.DrawBase().adjustX(-aBoundRect.Left());
267 rSalLayout.DrawBase().adjustY(-aBoundRect.Top());
268 rSalLayout.DrawText( *pVDev->mpGraphics );
269
270 Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
271 if ( aBmp.IsEmpty() || !aBmp.Rotate( mpFontInstance->mnOwnOrientation, COL_WHITE ) )
272 return false;
273
274 // calculate rotation offset
275 tools::Polygon aPoly( aBoundRect );
276 aPoly.Rotate( Point(), mpFontInstance->mnOwnOrientation );
277 Point aPoint = aPoly.GetBoundRect().TopLeft();
278 aPoint += Point( nX, nY );
279
280 // mask output with text colored bitmap
281 GDIMetaFile* pOldMetaFile = mpMetaFile;
282 tools::Long nOldOffX = mnOutOffX;
283 tools::Long nOldOffY = mnOutOffY;
284 bool bOldMap = mbMap;
285
286 mnOutOffX = 0;
287 mnOutOffY = 0;
288 mpMetaFile = nullptr;
289 EnableMapMode( false );
290
291 DrawMask( aPoint, aBmp, GetTextColor() );
292
293 EnableMapMode( bOldMap );
294 mnOutOffX = nOldOffX;
295 mnOutOffY = nOldOffY;
296 mpMetaFile = pOldMetaFile;
297
298 return true;
299}
300
302 bool bTextLines)
303{
304 if( mpFontInstance->mnOwnOrientation )
305 if( ImplDrawRotateText( rSalLayout ) )
306 return;
307
308 auto nOldX = rSalLayout.DrawBase().getX();
309 if( HasMirroredGraphics() )
310 {
312 auto x = rSalLayout.DrawBase().getX();
313 rSalLayout.DrawBase().setX( w - 1 - x );
314 if( !IsRTLEnabled() )
315 {
316 OutputDevice *pOutDevRef = this;
317 // mirror this window back
318 tools::Long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
319 rSalLayout.DrawBase().setX( devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().getX() - devX) ) ) ;
320 }
321 }
322 else if( IsRTLEnabled() )
323 {
324 OutputDevice *pOutDevRef = this;
325
326 // mirror this window back
327 tools::Long devX = pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
328 rSalLayout.DrawBase().setX( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().getX() - devX) + devX );
329 }
330
331 rSalLayout.DrawText( *mpGraphics );
332 rSalLayout.DrawBase().setX( nOldX );
333
334 if( bTextLines )
335 ImplDrawTextLines( rSalLayout,
338
339 // emphasis marks
340 if( maFont.GetEmphasisMark() & FontEmphasisMark::Style )
341 ImplDrawEmphasisMarks( rSalLayout );
342}
343
345{
346 Color aOldColor = GetTextColor();
347 Color aOldTextLineColor = GetTextLineColor();
348 Color aOldOverlineColor = GetOverlineColor();
349 FontRelief eRelief = maFont.GetRelief();
350
351 DevicePoint aOrigPos = rSalLayout.DrawBase();
352 if ( eRelief != FontRelief::NONE )
353 {
354 Color aReliefColor( COL_LIGHTGRAY );
355 Color aTextColor( aOldColor );
356
357 Color aTextLineColor( aOldTextLineColor );
358 Color aOverlineColor( aOldOverlineColor );
359
360 // we don't have an automatic color, so black is always drawn on white
361 if ( aTextColor == COL_BLACK )
362 aTextColor = COL_WHITE;
363 if ( aTextLineColor == COL_BLACK )
364 aTextLineColor = COL_WHITE;
365 if ( aOverlineColor == COL_BLACK )
366 aOverlineColor = COL_WHITE;
367
368 // relief-color is black for white text, in all other cases
369 // we set this to LightGray
370 // coverity[copy_paste_error: FALSE] - this is intentional
371 if ( aTextColor == COL_WHITE )
372 aReliefColor = COL_BLACK;
373 SetTextLineColor( aReliefColor );
374 SetOverlineColor( aReliefColor );
375 SetTextColor( aReliefColor );
377
378 // calculate offset - for high resolution printers the offset
379 // should be greater so that the effect is visible
380 tools::Long nOff = 1;
381 nOff += mnDPIX/300;
382
383 if ( eRelief == FontRelief::Engraved )
384 nOff = -nOff;
385 rSalLayout.DrawOffset() += Point( nOff, nOff);
386 ImplDrawTextDirect( rSalLayout, mbTextLines );
387 rSalLayout.DrawOffset() -= Point( nOff, nOff);
388
389 SetTextLineColor( aTextLineColor );
390 SetOverlineColor( aOverlineColor );
391 SetTextColor( aTextColor );
393 ImplDrawTextDirect( rSalLayout, mbTextLines );
394
395 SetTextLineColor( aOldTextLineColor );
396 SetOverlineColor( aOldOverlineColor );
397
398 if ( aTextColor != aOldColor )
399 {
400 SetTextColor( aOldColor );
402 }
403 }
404 else
405 {
406 if ( maFont.IsShadow() )
407 {
408 tools::Long nOff = 1 + ((mpFontInstance->mnLineHeight-24)/24);
409 if ( maFont.IsOutline() )
410 nOff++;
413 if ( (GetTextColor() == COL_BLACK)
414 || (GetTextColor().GetLuminance() < 8) )
416 else
419 rSalLayout.DrawBase() += DevicePoint( nOff, nOff );
420 ImplDrawTextDirect( rSalLayout, mbTextLines );
421 rSalLayout.DrawBase() -= DevicePoint( nOff, nOff );
422 SetTextColor( aOldColor );
423 SetTextLineColor( aOldTextLineColor );
424 SetOverlineColor( aOldOverlineColor );
426
427 if ( !maFont.IsOutline() )
428 ImplDrawTextDirect( rSalLayout, mbTextLines );
429 }
430
431 if ( maFont.IsOutline() )
432 {
433 rSalLayout.DrawBase() = aOrigPos + DevicePoint(-1,-1);
434 ImplDrawTextDirect( rSalLayout, mbTextLines );
435 rSalLayout.DrawBase() = aOrigPos + DevicePoint(+1,+1);
436 ImplDrawTextDirect( rSalLayout, mbTextLines );
437 rSalLayout.DrawBase() = aOrigPos + DevicePoint(-1,+0);
438 ImplDrawTextDirect( rSalLayout, mbTextLines );
439 rSalLayout.DrawBase() = aOrigPos + DevicePoint(-1,+1);
440 ImplDrawTextDirect( rSalLayout, mbTextLines );
441 rSalLayout.DrawBase() = aOrigPos + DevicePoint(+0,+1);
442 ImplDrawTextDirect( rSalLayout, mbTextLines );
443 rSalLayout.DrawBase() = aOrigPos + DevicePoint(+0,-1);
444 ImplDrawTextDirect( rSalLayout, mbTextLines );
445 rSalLayout.DrawBase() = aOrigPos + DevicePoint(+1,-1);
446 ImplDrawTextDirect( rSalLayout, mbTextLines );
447 rSalLayout.DrawBase() = aOrigPos + DevicePoint(+1,+0);
448 ImplDrawTextDirect( rSalLayout, mbTextLines );
449 rSalLayout.DrawBase() = aOrigPos;
450
455 ImplDrawTextDirect( rSalLayout, mbTextLines );
456 SetTextColor( aOldColor );
457 SetTextLineColor( aOldTextLineColor );
458 SetOverlineColor( aOldOverlineColor );
460 }
461 }
462}
463
465{
466
467 if( mbInitClipRegion )
469 if( mbOutputClipped )
470 return;
471 if( mbInitTextColor )
473
474 rSalLayout.DrawBase() += DevicePoint(mnTextOffX, mnTextOffY);
475
476 if( IsTextFillColor() )
477 ImplDrawTextBackground( rSalLayout );
478
479 if( mbTextSpecial )
480 ImplDrawSpecialText( rSalLayout );
481 else
482 ImplDrawTextDirect( rSalLayout, mbTextLines );
483}
484
486 ImplMultiTextLineInfo& rLineInfo,
487 tools::Long nWidth, const OUString& rStr,
488 DrawTextFlags nStyle, const vcl::ITextLayout& _rLayout )
489{
490 SAL_WARN_IF( nWidth <= 0, "vcl", "ImplGetTextLines: nWidth <= 0!" );
491
492 if ( nWidth <= 0 )
493 nWidth = 1;
494
495 rLineInfo.Clear();
496 if (rStr.isEmpty())
497 return 0;
498
499 const bool bClipping = (nStyle & DrawTextFlags::Clip) && !(nStyle & DrawTextFlags::EndEllipsis);
500
501 tools::Long nMaxLineWidth = 0;
503 css::uno::Reference< css::linguistic2::XHyphenator > xHyph;
504 if (bHyphenate)
505 {
506 // get service provider
507 css::uno::Reference<css::uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
508 css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLinguMgr = css::linguistic2::LinguServiceManager::create(xContext);
509 xHyph = xLinguMgr->getHyphenator();
510 }
511
512 css::uno::Reference<css::i18n::XBreakIterator> xBI;
513 sal_Int32 nPos = 0;
514 sal_Int32 nLen = rStr.getLength();
515 sal_Int32 nCurrentTextY = 0;
516 while ( nPos < nLen )
517 {
518 sal_Int32 nBreakPos = nPos;
519
520 while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( rStr[ nBreakPos ] != '\n' ) )
521 nBreakPos++;
522
523 tools::Long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
524 if ( ( nLineWidth > nWidth ) && ( nStyle & DrawTextFlags::WordBreak ) )
525 {
526 if ( !xBI.is() )
528
529 if ( xBI.is() )
530 {
531 nBreakPos = ImplBreakLinesWithIterator(nWidth, rStr, _rLayout, xHyph, xBI, bHyphenate, nPos, nBreakPos);
532 nLineWidth = _rLayout.GetTextWidth(rStr, nPos, nBreakPos - nPos);
533 }
534 else
535 // fallback to something really simple
536 nBreakPos = ImplBreakLinesSimple(nWidth, rStr, _rLayout, nPos, nBreakPos, nLineWidth);
537 }
538
539 if ( nLineWidth > nMaxLineWidth )
540 nMaxLineWidth = nLineWidth;
541
542 rLineInfo.AddLine( ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
543
544 if ( nBreakPos == nPos )
545 nBreakPos++;
546 nPos = nBreakPos;
547
548 if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] == '\n' ) ) )
549 {
550 nPos++;
551 // CR/LF?
552 if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ nPos-1 ] == '\r' ) )
553 nPos++;
554 }
555 nCurrentTextY += nTextHeight;
556 if (bClipping && nCurrentTextY > rRect.GetHeight())
557 break;
558 }
559
560#ifdef DBG_UTIL
561 for ( sal_Int32 nL = 0; nL < rLineInfo.Count(); nL++ )
562 {
563 ImplTextLineInfo& rLine = rLineInfo.GetLine( nL );
564 OUString aLine = rStr.copy( rLine.GetIndex(), rLine.GetLen() );
565 SAL_WARN_IF( aLine.indexOf( '\r' ) != -1, "vcl", "ImplGetTextLines - Found CR!" );
566 SAL_WARN_IF( aLine.indexOf( '\n' ) != -1, "vcl", "ImplGetTextLines - Found LF!" );
567 }
568#endif
569
570 return nMaxLineWidth;
571}
572
573sal_Int32 OutputDevice::ImplBreakLinesWithIterator(const tools::Long nWidth, const OUString& rStr, const vcl::ITextLayout& _rLayout,
574 const css::uno::Reference< css::linguistic2::XHyphenator >& xHyph,
575 const css::uno::Reference<css::i18n::XBreakIterator>& xBI,
576 const bool bHyphenate,
577 const sal_Int32 nPos, sal_Int32 nBreakPos)
578{
579 const css::lang::Locale& rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
580 sal_Int32 nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
581 if (nSoftBreak == -1)
582 {
583 nSoftBreak = nPos;
584 }
585 SAL_WARN_IF( nSoftBreak >= nBreakPos, "vcl", "Break?!" );
586 css::i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, css::uno::Sequence <css::beans::PropertyValue>(), 1 );
587 css::i18n::LineBreakUserOptions aUserOptions;
588 css::i18n::LineBreakResults aLBR = xBI->getLineBreak( rStr, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
589 nBreakPos = aLBR.breakIndex;
590 if ( nBreakPos <= nPos )
591 nBreakPos = nSoftBreak;
592 if ( !bHyphenate )
593 return nBreakPos;
594
595 // Whether hyphen or not: Put the word after the hyphen through
596 // word boundary.
597
598 // nMaxBreakPos the last char that fits into the line
599 // nBreakPos is the word's start
600
601 // We run into a problem if the doc is so narrow, that a word
602 // is broken into more than two lines ...
603 if ( !xHyph.is() )
604 return nBreakPos;
605
606 css::i18n::Boundary aBoundary = xBI->getWordBoundary( rStr, nBreakPos, rDefLocale, css::i18n::WordType::DICTIONARY_WORD, true );
607 sal_Int32 nWordStart = nPos;
608 sal_Int32 nWordEnd = aBoundary.endPos;
609 SAL_WARN_IF( nWordEnd <= nWordStart, "vcl", "ImpBreakLine: Start >= End?" );
610
611 sal_Int32 nWordLen = nWordEnd - nWordStart;
612 if ( ( nWordEnd < nSoftBreak ) || ( nWordLen <= 3 ) )
613 return nBreakPos;
614
615 // #104415# May happen, because getLineBreak may differ from getWordBoundary with DICTIONARY_WORD
616 // SAL_WARN_IF( nWordEnd < nMaxBreakPos, "vcl", "Hyph: Break?" );
617 OUString aWord = rStr.copy( nWordStart, nWordLen );
618 sal_Int32 nMinTrail = nWordEnd-nSoftBreak+1; //+1: Before the "broken off" char
619 css::uno::Reference< css::linguistic2::XHyphenatedWord > xHyphWord;
620 if (xHyph.is())
621 xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.getLength() - nMinTrail, css::uno::Sequence< css::beans::PropertyValue >() );
622 if (!xHyphWord.is())
623 return nBreakPos;
624
625 bool bAlternate = xHyphWord->isAlternativeSpelling();
626 sal_Int32 _nWordLen = 1 + xHyphWord->getHyphenPos();
627
628 if ( ( _nWordLen < 2 ) || ( (nWordStart+_nWordLen) < 2 ) )
629 return nBreakPos;
630
631 if ( bAlternate )
632 {
633 nBreakPos = nWordStart + _nWordLen;
634 return nBreakPos;
635 }
636
637
638 OUString aAlt( xHyphWord->getHyphenatedWord() );
639
640 // We can have two cases:
641 // 1) "packen" turns into "pak-ken"
642 // 2) "Schiffahrt" turns into "Schiff-fahrt"
643
644 // In case 1 we need to replace a char
645 // In case 2 we add a char
646
647 // Correct recognition is made harder by words such as
648 // "Schiffahrtsbrennesseln", as the Hyphenator splits all
649 // positions of the word and comes up with "Schifffahrtsbrennnesseln"
650 // Thus, we cannot infer the aWord from the AlternativeWord's
651 // index.
652 // TODO: The whole junk will be made easier by a function in
653 // the Hyphenator, as soon as AMA adds it.
654 sal_Int32 nAltStart = _nWordLen - 1;
655 sal_Int32 nTxtStart = nAltStart - (aAlt.getLength() - aWord.getLength());
656 sal_Int32 nTxtEnd = nTxtStart;
657 sal_Int32 nAltEnd = nAltStart;
658
659 // The area between nStart and nEnd is the difference
660 // between AlternativeString and OriginalString
661 while( nTxtEnd < aWord.getLength() && nAltEnd < aAlt.getLength() &&
662 aWord[nTxtEnd] != aAlt[nAltEnd] )
663 {
664 ++nTxtEnd;
665 ++nAltEnd;
666 }
667
668 // If a char was added, we notice it now:
669 if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
670 aWord[ nTxtEnd ] == aAlt[nAltEnd] )
671 {
672 ++nAltEnd;
673 ++nTxtStart;
674 ++nTxtEnd;
675 }
676
677 SAL_WARN_IF( ( nAltEnd - nAltStart ) != 1, "vcl", "Alternate: Wrong assumption!" );
678
679 sal_Unicode cAlternateReplChar = 0;
680 if ( nTxtEnd > nTxtStart )
681 cAlternateReplChar = aAlt[ nAltStart ];
682
683 nBreakPos = nWordStart + nTxtStart;
684 if ( cAlternateReplChar )
685 nBreakPos++;
686 return nBreakPos;
687}
688
689sal_Int32 OutputDevice::ImplBreakLinesSimple( const tools::Long nWidth, const OUString& rStr,
690 const vcl::ITextLayout& _rLayout, const sal_Int32 nPos, sal_Int32 nBreakPos, tools::Long& nLineWidth )
691{
692 sal_Int32 nSpacePos = rStr.getLength();
693 tools::Long nW = 0;
694 do
695 {
696 nSpacePos = rStr.lastIndexOf( ' ', nSpacePos );
697 if( nSpacePos != -1 )
698 {
699 if( nSpacePos > nPos )
700 nSpacePos--;
701 nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
702 }
703 } while( nW > nWidth );
704
705 if( nSpacePos != -1 )
706 {
707 nBreakPos = nSpacePos;
708 nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
709 if( nBreakPos < rStr.getLength()-1 )
710 nBreakPos++;
711 }
712 return nBreakPos;
713}
714
715
716void OutputDevice::SetTextColor( const Color& rColor )
717{
718
719 Color aColor(vcl::drawmode::GetTextColor(rColor, GetDrawMode(), GetSettings().GetStyleSettings()));
720
721 if ( mpMetaFile )
722 mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
723
724 if ( maTextColor != aColor )
725 {
726 maTextColor = aColor;
727 mbInitTextColor = true;
728 }
729
730 if( mpAlphaVDev )
731 mpAlphaVDev->SetTextColor( COL_BLACK );
732}
733
734void OutputDevice::SetTextFillColor()
735{
736
737 if ( mpMetaFile )
738 mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), false ) );
739
740 if ( maFont.GetColor() != COL_TRANSPARENT ) {
741 maFont.SetFillColor( COL_TRANSPARENT );
742 }
743 if ( !maFont.IsTransparent() )
744 maFont.SetTransparent( true );
745
746 if( mpAlphaVDev )
747 mpAlphaVDev->SetTextFillColor();
748}
749
750void OutputDevice::SetTextFillColor( const Color& rColor )
751{
752 Color aColor(vcl::drawmode::GetFillColor(rColor, GetDrawMode(), GetSettings().GetStyleSettings()));
753
754 if ( mpMetaFile )
755 mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, true ) );
756
757 if ( maFont.GetFillColor() != aColor )
758 maFont.SetFillColor( aColor );
759 if ( maFont.IsTransparent() != rColor.IsTransparent() )
760 maFont.SetTransparent( rColor.IsTransparent() );
761
762 if( mpAlphaVDev )
763 mpAlphaVDev->SetTextFillColor( COL_BLACK );
764}
765
766Color OutputDevice::GetTextFillColor() const
767{
768 if ( maFont.IsTransparent() )
769 return COL_TRANSPARENT;
770 else
771 return maFont.GetFillColor();
772}
773
774void OutputDevice::SetTextAlign( TextAlign eAlign )
775{
776
777 if ( mpMetaFile )
778 mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
779
780 if ( maFont.GetAlignment() != eAlign )
781 {
782 maFont.SetAlignment( eAlign );
783 mbNewFont = true;
784 }
785
786 if( mpAlphaVDev )
787 mpAlphaVDev->SetTextAlign( eAlign );
788}
789
790vcl::Region OutputDevice::GetOutputBoundsClipRegion() const
791{
792 return GetClipRegion();
793}
794
795const SalLayoutFlags eDefaultLayout = SalLayoutFlags::NONE;
796
797void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
798 sal_Int32 nIndex, sal_Int32 nLen,
799 std::vector< tools::Rectangle >* pVector, OUString* pDisplayText,
800 const SalLayoutGlyphs* pLayoutCache
801 )
802{
803 assert(!is_double_buffered_window());
804
805 if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
806 {
807 nLen = rStr.getLength() - nIndex;
808 }
809
810 if (mpOutDevData->mpRecordLayout)
811 {
812 pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
813 pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
814 }
815
816#if OSL_DEBUG_LEVEL > 2
817 SAL_INFO("vcl.gdi", "OutputDevice::DrawText(\"" << rStr << "\")");
818#endif
819
820 if ( mpMetaFile )
821 mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
822 if( pVector )
823 {
825
826 if (mpOutDevData->mpRecordLayout)
827 {
828 mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.getLength() );
829 aClip.Intersect( mpOutDevData->maRecordRect );
830 }
831 if( ! aClip.IsNull() )
832 {
833 std::vector< tools::Rectangle > aTmp;
834 GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, aTmp );
835
836 bool bInserted = false;
837 for( std::vector< tools::Rectangle >::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
838 {
839 bool bAppend = false;
840
841 if( aClip.Overlaps( *it ) )
842 bAppend = true;
843 else if( rStr[ nIndex ] == ' ' && bInserted )
844 {
845 std::vector< tools::Rectangle >::const_iterator next = it;
846 ++next;
847 if( next != aTmp.end() && aClip.Overlaps( *next ) )
848 bAppend = true;
849 }
850
851 if( bAppend )
852 {
853 pVector->push_back( *it );
854 if( pDisplayText )
855 *pDisplayText += OUStringChar(rStr[ nIndex ]);
856 bInserted = true;
857 }
858 }
859 }
860 else
861 {
862 GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, *pVector );
863 if( pDisplayText )
864 *pDisplayText += rStr.subView( nIndex, nLen );
865 }
866 }
867
868 if ( !IsDeviceOutputNecessary() || pVector )
869 return;
870
872 // do not use cache with modified string
873 if(mpFontInstance->mpConversion)
874 pLayoutCache = nullptr;
875
876 std::unique_ptr<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, {}, {}, eDefaultLayout, nullptr, pLayoutCache);
877 if(pSalLayout)
878 {
879 ImplDrawText( *pSalLayout );
880 }
881
882 if( mpAlphaVDev )
883 mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
884}
885
886tools::Long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen,
887 vcl::text::TextLayoutCache const*const pLayoutCache,
888 SalLayoutGlyphs const*const pSalLayoutCache) const
889{
890
891 tools::Long nWidth = GetTextArray( rStr, nullptr, nIndex,
892 nLen, false, pLayoutCache, pSalLayoutCache );
893
894 return nWidth;
895}
896
898{
899 if (!InitFont())
900 return 0;
901
903
904 if ( mbMap )
905 nHeight = ImplDevicePixelToLogicHeight( nHeight );
906
907 return nHeight;
908}
909
911{
912 //note pango uses "The quick brown fox jumps over the lazy dog." for english
913 //and has a bunch of per-language strings which corresponds somewhat with
914 //makeRepresentativeText in include/svtools/sampletext.hxx
915 return GetTextWidth("aemnnxEM") / 8.0;
916}
917
919{
920 return GetTextWidth("0123456789") / 10.0;
921}
922
923void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr,
925 o3tl::span<const sal_Bool> pKashidaAry,
926 sal_Int32 nIndex, sal_Int32 nLen, SalLayoutFlags flags,
927 const SalLayoutGlyphs* pSalLayoutCache )
928{
929 assert(!is_double_buffered_window());
930
931 if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
932 {
933 nLen = rStr.getLength() - nIndex;
934 }
935 if ( mpMetaFile )
936 mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen ) );
937
939 return;
940 if( !mpGraphics && !AcquireGraphics() )
941 return;
942 assert(mpGraphics);
943 if( mbInitClipRegion )
945 if( mbOutputClipped )
946 return;
947
948 std::unique_ptr<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry, pKashidaAry, flags, nullptr, pSalLayoutCache);
949 if( pSalLayout )
950 {
951 ImplDrawText( *pSalLayout );
952 }
953
954 if( mpAlphaVDev )
955 mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen, flags );
956}
957
958tools::Long OutputDevice::GetTextArray( const OUString& rStr, std::vector<sal_Int32>* pDXAry,
959 sal_Int32 nIndex, sal_Int32 nLen, bool bCaret,
960 vcl::text::TextLayoutCache const*const pLayoutCache,
961 SalLayoutGlyphs const*const pSalLayoutCache) const
962{
963 if( nIndex >= rStr.getLength() )
964 return 0; // TODO: this looks like a buggy caller?
965
966 if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
967 {
968 nLen = rStr.getLength() - nIndex;
969 }
970
971 // do layout
972 std::unique_ptr<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen,
973 Point(0,0), 0, {}, {}, eDefaultLayout, pLayoutCache, pSalLayoutCache);
974 if( !pSalLayout )
975 {
976 // The caller expects this to init the elements of pDXAry.
977 // Adapting all the callers to check that GetTextArray succeeded seems
978 // too much work.
979 // Init here to 0 only in the (rare) error case, so that any missing
980 // element init in the happy case will still be found by tools,
981 // and hope that is sufficient.
982 if (pDXAry)
983 {
984 pDXAry->resize(nLen);
985 std::fill(pDXAry->begin(), pDXAry->end(), 0);
986 }
987 return 0;
988 }
989
990#if VCL_FLOAT_DEVICE_PIXEL
991 std::unique_ptr<std::vector<DeviceCoordinate>> xDXPixelArray;
992 if(pDXAry)
993 {
994 xDXPixelArray.reset(new std::vector<DeviceCoordinate>(nLen));
995 }
996 std::vector<DeviceCoordinate>* pDXPixelArray = xDXPixelArray.get();
997 DeviceCoordinate nWidth = pSalLayout->FillDXArray(pDXPixelArray, bCaret ? rStr : OUString());
998 int nWidthFactor = pSalLayout->GetUnitsPerPixel();
999
1000 // convert virtual char widths to virtual absolute positions
1001 if( pDXPixelArray )
1002 {
1003 for( int i = 1; i < nLen; ++i )
1004 {
1005 (*pDXPixelArray)[i] += (*pDXPixelArray)[i - 1];
1006 }
1007 }
1008 if( mbMap )
1009 {
1010 if( pDXPixelArray )
1011 {
1012 for( int i = 0; i < nLen; ++i )
1013 {
1014 (*pDXPixelArray)[i] = ImplDevicePixelToLogicWidth((*pDXPixelArray)[i]);
1015 }
1016 }
1017 nWidth = ImplDevicePixelToLogicWidth( nWidth );
1018 }
1019 if( nWidthFactor > 1 )
1020 {
1021 if( pDXPixelArray )
1022 {
1023 for( int i = 0; i < nLen; ++i )
1024 {
1025 (*pDXPixelArray)[i] /= nWidthFactor;
1026 }
1027 }
1028 nWidth /= nWidthFactor;
1029 }
1030 if(pDXAry)
1031 {
1032 pDXAry->resize(nLen);
1033 for( int i = 0; i < nLen; ++i )
1034 {
1035 (*pDXAry)[i] = basegfx::fround((*pDXPixelArray)[i]);
1036 }
1037 }
1038 return basegfx::fround(nWidth);
1039
1040#else /* ! VCL_FLOAT_DEVICE_PIXEL */
1041
1042 tools::Long nWidth = pSalLayout->FillDXArray( pDXAry, bCaret ? rStr : OUString() );
1043 int nWidthFactor = pSalLayout->GetUnitsPerPixel();
1044
1045 // convert virtual char widths to virtual absolute positions
1046 if( pDXAry )
1047 for( int i = 1; i < nLen; ++i )
1048 (*pDXAry)[ i ] += (*pDXAry)[ i-1 ];
1049
1050 // convert from font units to logical units
1051 if( mbMap )
1052 {
1053 if( pDXAry )
1054 for( int i = 0; i < nLen; ++i )
1055 (*pDXAry)[i] = ImplDevicePixelToLogicWidth( (*pDXAry)[i] );
1056 nWidth = ImplDevicePixelToLogicWidth( nWidth );
1057 }
1058
1059 if( nWidthFactor > 1 )
1060 {
1061 if( pDXAry )
1062 for( int i = 0; i < nLen; ++i )
1063 (*pDXAry)[i] /= nWidthFactor;
1064 nWidth /= nWidthFactor;
1065 }
1066 return nWidth;
1067#endif /* VCL_FLOAT_DEVICE_PIXEL */
1068}
1069
1070void OutputDevice::GetCaretPositions( const OUString& rStr, sal_Int32* pCaretXArray,
1071 sal_Int32 nIndex, sal_Int32 nLen,
1072 const SalLayoutGlyphs* pGlyphs ) const
1073{
1074
1075 if( nIndex >= rStr.getLength() )
1076 return;
1077 if( nIndex+nLen >= rStr.getLength() )
1078 nLen = rStr.getLength() - nIndex;
1079
1080 // layout complex text
1081 std::unique_ptr<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, Point(0, 0), 0, {}, {},
1082 eDefaultLayout, nullptr, pGlyphs);
1083 if( !pSalLayout )
1084 {
1085 std::fill(pCaretXArray, pCaretXArray + nLen * 2, -1);
1086 return;
1087 }
1088
1089 int nWidthFactor = pSalLayout->GetUnitsPerPixel();
1090 pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
1091 tools::Long nWidth = pSalLayout->GetTextWidth();
1092
1093 // fixup unknown caret positions
1094 int i;
1095 for( i = 0; i < 2 * nLen; ++i )
1096 if( pCaretXArray[ i ] >= 0 )
1097 break;
1098 tools::Long nXPos = (i < 2 * nLen) ? pCaretXArray[i] : -1;
1099 for( i = 0; i < 2 * nLen; ++i )
1100 {
1101 if( pCaretXArray[ i ] >= 0 )
1102 nXPos = pCaretXArray[ i ];
1103 else
1104 pCaretXArray[ i ] = nXPos;
1105 }
1106
1107 // handle window mirroring
1108 if( IsRTLEnabled() )
1109 {
1110 for( i = 0; i < 2 * nLen; ++i )
1111 pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
1112 }
1113
1114 // convert from font units to logical units
1115 if( mbMap )
1116 {
1117 for( i = 0; i < 2*nLen; ++i )
1118 pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
1119 }
1120
1121 if( nWidthFactor != 1 )
1122 {
1123 for( i = 0; i < 2*nLen; ++i )
1124 pCaretXArray[i] /= nWidthFactor;
1125 }
1126}
1127
1128void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
1129 const OUString& rStr,
1130 sal_Int32 nIndex, sal_Int32 nLen)
1131{
1132 assert(!is_double_buffered_window());
1133
1134 if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
1135 {
1136 nLen = rStr.getLength() - nIndex;
1137 }
1138
1139 if ( mpMetaFile )
1140 mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
1141
1142 if ( !IsDeviceOutputNecessary() )
1143 return;
1144
1145 std::unique_ptr<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, nWidth);
1146 if( pSalLayout )
1147 {
1148 ImplDrawText( *pSalLayout );
1149 }
1150
1151 if( mpAlphaVDev )
1152 mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
1153}
1154
1156 const sal_Int32 nMinIndex, const sal_Int32 nLen,
1157 DeviceCoordinate nPixelWidth,
1158 SalLayoutFlags nLayoutFlags,
1159 vcl::text::TextLayoutCache const*const pLayoutCache) const
1160{
1161 assert(nMinIndex >= 0);
1162 assert(nLen >= 0);
1163
1164 // get string length for calculating extents
1165 sal_Int32 nEndIndex = rStr.getLength();
1166 if( nMinIndex + nLen < nEndIndex )
1167 nEndIndex = nMinIndex + nLen;
1168
1169 // don't bother if there is nothing to do
1170 if( nEndIndex < nMinIndex )
1171 nEndIndex = nMinIndex;
1172
1173 nLayoutFlags |= GetBiDiLayoutFlags( rStr, nMinIndex, nEndIndex );
1174
1175 if( !maFont.IsKerning() )
1176 nLayoutFlags |= SalLayoutFlags::DisableKerning;
1178 nLayoutFlags |= SalLayoutFlags::KerningAsian;
1179 if( maFont.IsVertical() )
1180 nLayoutFlags |= SalLayoutFlags::Vertical;
1181 if( maFont.IsFixKerning() ||
1182 ( mpFontInstance && mpFontInstance->GetFontSelectPattern().GetPitch() == PITCH_FIXED ) )
1183 nLayoutFlags |= SalLayoutFlags::DisableLigatures;
1184
1185 if( meTextLanguage ) //TODO: (mnTextLayoutMode & vcl::text::ComplexTextLayoutFlags::SubstituteDigits)
1186 {
1187 // disable character localization when no digits used
1188 const sal_Unicode* pBase = rStr.getStr();
1189 const sal_Unicode* pStr = pBase + nMinIndex;
1190 const sal_Unicode* pEnd = pBase + nEndIndex;
1191 std::optional<OUStringBuffer> xTmpStr;
1192 for( ; pStr < pEnd; ++pStr )
1193 {
1194 // TODO: are there non-digit localizations?
1195 if( (*pStr >= '0') && (*pStr <= '9') )
1196 {
1197 // translate characters to local preference
1198 sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
1199 if( cChar != *pStr )
1200 {
1201 if (!xTmpStr)
1202 xTmpStr = OUStringBuffer(rStr);
1203 // TODO: are the localized digit surrogates?
1204 (*xTmpStr)[pStr - pBase] = cChar;
1205 }
1206 }
1207 }
1208 if (xTmpStr)
1209 rStr = (*xTmpStr).makeStringAndClear();
1210 }
1211
1212 // right align for RTL text, DRAWPOS_REVERSED, RTL window style
1215 bRightAlign = false;
1217 bRightAlign = true;
1218 // SSA: hack for western office, ie text get right aligned
1219 // for debugging purposes of mirrored UI
1220 bool bRTLWindow = IsRTLEnabled();
1221 bRightAlign ^= bRTLWindow;
1222 if( bRightAlign )
1223 nLayoutFlags |= SalLayoutFlags::RightAlign;
1224
1225 // set layout options
1226 vcl::text::ImplLayoutArgs aLayoutArgs(rStr, nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag(), pLayoutCache);
1227
1228 Degree10 nOrientation = mpFontInstance ? mpFontInstance->mnOrientation : 0_deg10;
1229 aLayoutArgs.SetOrientation( nOrientation );
1230
1231 aLayoutArgs.SetLayoutWidth( nPixelWidth );
1232
1233 return aLayoutArgs;
1234}
1235
1237 const sal_Int32 nMinIndex,
1238 const sal_Int32 nEndIndex ) const
1239{
1240 SalLayoutFlags nLayoutFlags = SalLayoutFlags::NONE;
1242 nLayoutFlags |= SalLayoutFlags::BiDiRtl;
1244 nLayoutFlags |= SalLayoutFlags::BiDiStrong;
1246 {
1247 // Disable Bidi if no RTL hint and only known LTR codes used.
1248 bool bAllLtr = true;
1249 for (sal_Int32 i = nMinIndex; i < nEndIndex; i++)
1250 {
1251 // [0x0000, 0x052F] are Latin, Greek and Cyrillic.
1252 // [0x0370, 0x03FF] has a few holes as if Unicode 10.0.0, but
1253 // hopefully no RTL character will be encoded there.
1254 if (rStr[i] > 0x052F)
1255 {
1256 bAllLtr = false;
1257 break;
1258 }
1259 }
1260 if (bAllLtr)
1261 nLayoutFlags |= SalLayoutFlags::BiDiStrong;
1262 }
1263 return nLayoutFlags;
1264}
1265
1267
1268static inline bool IsTrackingFontMappingUse()
1269{
1270 return fontMappingUseData != nullptr;
1271}
1272
1273static void TrackFontMappingUse( const vcl::Font& originalFont, const SalLayout* salLayout)
1274{
1275 assert(fontMappingUseData);
1276 OUString originalName = originalFont.GetStyleName().isEmpty()
1277 ? originalFont.GetFamilyName()
1278 : originalFont.GetFamilyName() + "/" + originalFont.GetStyleName();
1279 std::vector<OUString> usedFontNames;
1280 SalLayoutGlyphs glyphs = salLayout->GetGlyphs(); // includes all font fallbacks
1281 int level = 0;
1282 while( const SalLayoutGlyphsImpl* impl = glyphs.Impl(level++))
1283 {
1284 const vcl::font::PhysicalFontFace* face = impl->GetFont()->GetFontFace();
1285 OUString name = face->GetStyleName().isEmpty()
1286 ? face->GetFamilyName()
1287 : face->GetFamilyName() + "/" + face->GetStyleName();
1288 usedFontNames.push_back( name );
1289 }
1291 {
1292 if( item.mOriginalFont == originalName && item.mUsedFonts == usedFontNames )
1293 {
1294 ++item.mCount;
1295 return;
1296 }
1297 }
1298 fontMappingUseData->push_back( { originalName, usedFontNames, 1 } );
1299}
1300
1302{
1303 delete fontMappingUseData;
1305}
1306
1308{
1310 return {};
1311 FontMappingUseData ret = std::move( *fontMappingUseData );
1312 delete fontMappingUseData;
1313 fontMappingUseData = nullptr;
1314 return ret;
1315}
1316
1317std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr,
1318 sal_Int32 nMinIndex, sal_Int32 nLen,
1319 const Point& rLogicalPos, tools::Long nLogicalWidth,
1321 o3tl::span<const sal_Bool> pKashidaArray,
1322 SalLayoutFlags flags,
1323 vcl::text::TextLayoutCache const* pLayoutCache,
1324 const SalLayoutGlyphs* pGlyphs) const
1325{
1326 if (pGlyphs && !pGlyphs->IsValid())
1327 {
1328 SAL_WARN("vcl", "Trying to setup invalid cached glyphs - falling back to relayout!");
1329 pGlyphs = nullptr;
1330 }
1331#ifdef DBG_UTIL
1332 if (pGlyphs)
1333 {
1334 for( int level = 0;; ++level )
1335 {
1336 SalLayoutGlyphsImpl* glyphsImpl = pGlyphs->Impl(level);
1337 if(glyphsImpl == nullptr)
1338 break;
1339 // It is allowed to reuse only glyphs created with SalLayoutFlags::GlyphItemsOnly.
1340 // If the glyphs have already been used, the AdjustLayout() call below might have
1341 // altered them (MultiSalLayout::ImplAdjustMultiLayout() drops glyphs that need
1342 // fallback from the base layout, but then GenericSalLayout::LayoutText()
1343 // would not know to call SetNeedFallback()).
1344 assert(glyphsImpl->GetFlags() & SalLayoutFlags::GlyphItemsOnly);
1345 }
1346 }
1347#endif
1348
1349 if (!InitFont())
1350 return nullptr;
1351
1352 // check string index and length
1353 if( -1 == nLen || nMinIndex + nLen > rOrigStr.getLength() )
1354 {
1355 const sal_Int32 nNewLen = rOrigStr.getLength() - nMinIndex;
1356 if( nNewLen <= 0 )
1357 return nullptr;
1358 nLen = nNewLen;
1359 }
1360
1361 OUString aStr = rOrigStr;
1362
1363 // recode string if needed
1364 if( mpFontInstance->mpConversion ) {
1365 mpFontInstance->mpConversion->RecodeString( aStr, 0, aStr.getLength() );
1366 pLayoutCache = nullptr; // don't use cache with modified string!
1367 pGlyphs = nullptr;
1368 }
1369
1370 DeviceCoordinate nPixelWidth = static_cast<DeviceCoordinate>(nLogicalWidth);
1371 if( nLogicalWidth && mbMap )
1372 {
1373 // convert from logical units to physical units
1374 nPixelWidth = LogicWidthToDeviceCoordinate( nLogicalWidth );
1375 }
1376
1377 vcl::text::ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen,
1378 nPixelWidth, flags, pLayoutCache);
1379
1380 bool bHasScaledDXArray(false);
1381 DeviceCoordinate nEndGlyphCoord(0);
1382 std::unique_ptr<double[]> xNaturalDXPixelArray;
1383 if( !pDXArray.empty() )
1384 {
1385 xNaturalDXPixelArray.reset(new double[nLen]);
1386
1387 if (mbMap)
1388 {
1389 // convert from logical units to font units without rounding,
1390 // keeping accuracy for lower levels
1391 bHasScaledDXArray = true;
1392 for (int i = 0; i < nLen; ++i)
1393 xNaturalDXPixelArray[i] = ImplLogicWidthToDeviceSubPixel(pDXArray[i]);
1394 }
1395 else
1396 {
1397 for(int i = 0; i < nLen; ++i)
1398 xNaturalDXPixelArray[i] = pDXArray[i];
1399 }
1400
1401 aLayoutArgs.SetNaturalDXArray(xNaturalDXPixelArray.get());
1402 nEndGlyphCoord = std::lround(xNaturalDXPixelArray[nLen - 1]);
1403 }
1404
1405 if (!pKashidaArray.empty())
1406 aLayoutArgs.SetKashidaArray(pKashidaArray.data());
1407
1408 // get matching layout object for base font
1409 std::unique_ptr<SalLayout> pSalLayout = mpGraphics->GetTextLayout(0);
1410
1411 // layout text
1412 if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs, pGlyphs ? pGlyphs->Impl(0) : nullptr ) )
1413 {
1414 pSalLayout.reset();
1415 }
1416
1417 if( !pSalLayout )
1418 return nullptr;
1419
1420 pSalLayout->SetTextRenderModeForResolutionIndependentLayout(bHasScaledDXArray);
1421
1422 // do glyph fallback if needed
1423 // #105768# avoid fallback for very small font sizes
1424 if (aLayoutArgs.HasFallbackRun() && mpFontInstance->GetFontSelectPattern().mnHeight >= 3)
1425 pSalLayout = ImplGlyphFallbackLayout(std::move(pSalLayout), aLayoutArgs, pGlyphs);
1426
1428 // Return glyph items only after fallback handling. Otherwise they may
1429 // contain invalid glyph IDs.
1430 return pSalLayout;
1431
1432 // position, justify, etc. the layout
1433 pSalLayout->AdjustLayout( aLayoutArgs );
1434
1435 // default to on for pdf export which uses SubPixelToLogic to convert back to
1436 // the logical coord space, default off for everything else for now unless
1437 // a dxarray is provided which has to be scaled
1438 if (bHasScaledDXArray || meOutDevType == OUTDEV_PDF)
1439 pSalLayout->DrawBase() = ImplLogicToDeviceSubPixel(rLogicalPos);
1440 else
1441 {
1442 Point aDevicePos = ImplLogicToDevicePixel(rLogicalPos);
1443 pSalLayout->DrawBase() = DevicePoint(aDevicePos.X(), aDevicePos.Y());
1444 }
1445
1446 // adjust to right alignment if necessary
1447 if( aLayoutArgs.mnFlags & SalLayoutFlags::RightAlign )
1448 {
1449 DeviceCoordinate nRTLOffset;
1450 if (!pDXArray.empty())
1451 nRTLOffset = nEndGlyphCoord;
1452 else if( nPixelWidth )
1453 nRTLOffset = nPixelWidth;
1454 else
1455 nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
1456 pSalLayout->DrawOffset().setX( 1 - nRTLOffset );
1457 }
1458
1460 TrackFontMappingUse(GetFont(), pSalLayout.get());
1461
1462 return pSalLayout;
1463}
1464
1465std::shared_ptr<const vcl::text::TextLayoutCache> OutputDevice::CreateTextLayoutCache(
1466 OUString const& rString)
1467{
1468 return vcl::text::TextLayoutCache::Create(rString);
1469}
1470
1471bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const
1472{
1473 OUString aStr( rString );
1475 bool bRTL = false;
1476 int nCharPos = -1;
1477 if (!aArgs.GetNextPos(&nCharPos, &bRTL))
1478 return false;
1479 return (nCharPos != nIndex);
1480}
1481
1482sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, tools::Long nTextWidth,
1483 sal_Int32 nIndex, sal_Int32 nLen,
1484 tools::Long nCharExtra,
1485 vcl::text::TextLayoutCache const*const pLayoutCache,
1486 const SalLayoutGlyphs* pGlyphs) const
1487{
1488 std::unique_ptr<SalLayout> pSalLayout = ImplLayout( rStr, nIndex, nLen,
1489 Point(0,0), 0, {}, {}, eDefaultLayout, pLayoutCache, pGlyphs);
1490 sal_Int32 nRetVal = -1;
1491 if( pSalLayout )
1492 {
1493 // convert logical widths into layout units
1494 // NOTE: be very careful to avoid rounding errors for nCharExtra case
1495 // problem with rounding errors especially for small nCharExtras
1496 // TODO: remove when layout units have subpixel granularity
1497 tools::Long nWidthFactor = pSalLayout->GetUnitsPerPixel();
1498 tools::Long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
1499 nTextWidth *= nWidthFactor * nSubPixelFactor;
1500 DeviceCoordinate nTextPixelWidth = LogicWidthToDeviceCoordinate( nTextWidth );
1501 DeviceCoordinate nExtraPixelWidth = 0;
1502 if( nCharExtra != 0 )
1503 {
1504 nCharExtra *= nWidthFactor * nSubPixelFactor;
1505 nExtraPixelWidth = LogicWidthToDeviceCoordinate( nCharExtra );
1506 }
1507 nRetVal = pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor );
1508 }
1509
1510 return nRetVal;
1511}
1512
1513sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, tools::Long nTextWidth,
1514 sal_Unicode nHyphenChar, sal_Int32& rHyphenPos,
1515 sal_Int32 nIndex, sal_Int32 nLen,
1516 tools::Long nCharExtra,
1517 vcl::text::TextLayoutCache const*const pLayoutCache,
1518 const SalLayoutGlyphs* pGlyphs) const
1519{
1520 rHyphenPos = -1;
1521
1522 std::unique_ptr<SalLayout> pSalLayout = ImplLayout( rStr, nIndex, nLen,
1523 Point(0,0), 0, {}, {}, eDefaultLayout, pLayoutCache, pGlyphs);
1524 sal_Int32 nRetVal = -1;
1525 if( pSalLayout )
1526 {
1527 // convert logical widths into layout units
1528 // NOTE: be very careful to avoid rounding errors for nCharExtra case
1529 // problem with rounding errors especially for small nCharExtras
1530 // TODO: remove when layout units have subpixel granularity
1531 tools::Long nWidthFactor = pSalLayout->GetUnitsPerPixel();
1532 tools::Long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
1533
1534 nTextWidth *= nWidthFactor * nSubPixelFactor;
1535 DeviceCoordinate nTextPixelWidth = LogicWidthToDeviceCoordinate( nTextWidth );
1536 DeviceCoordinate nExtraPixelWidth = 0;
1537 if( nCharExtra != 0 )
1538 {
1539 nCharExtra *= nWidthFactor * nSubPixelFactor;
1540 nExtraPixelWidth = LogicWidthToDeviceCoordinate( nCharExtra );
1541 }
1542
1543 // calculate un-hyphenated break position
1544 nRetVal = pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor );
1545
1546 // calculate hyphenated break position
1547 OUString aHyphenStr(nHyphenChar);
1548 std::unique_ptr<SalLayout> pHyphenLayout = ImplLayout( aHyphenStr, 0, 1 );
1549 if( pHyphenLayout )
1550 {
1551 // calculate subpixel width of hyphenation character
1552 tools::Long nHyphenPixelWidth = pHyphenLayout->GetTextWidth() * nSubPixelFactor;
1553
1554 // calculate hyphenated break position
1555 nTextPixelWidth -= nHyphenPixelWidth;
1556 if( nExtraPixelWidth > 0 )
1557 nTextPixelWidth -= nExtraPixelWidth;
1558
1559 rHyphenPos = pSalLayout->GetTextBreak(nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor);
1560
1561 if( rHyphenPos > nRetVal )
1562 rHyphenPos = nRetVal;
1563 }
1564 }
1565
1566 return nRetVal;
1567}
1568
1570 const OUString& rOrigStr, DrawTextFlags nStyle,
1571 std::vector< tools::Rectangle >* pVector, OUString* pDisplayText,
1572 vcl::ITextLayout& _rLayout )
1573{
1574
1575 Color aOldTextColor;
1576 Color aOldTextFillColor;
1577 bool bRestoreFillColor = false;
1578 if ( (nStyle & DrawTextFlags::Disable) && ! pVector )
1579 {
1580 bool bHighContrastBlack = false;
1581 bool bHighContrastWhite = false;
1582 const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
1583 if( rStyleSettings.GetHighContrastMode() )
1584 {
1585 Color aCol;
1586 if( rTargetDevice.IsBackground() )
1587 aCol = rTargetDevice.GetBackground().GetColor();
1588 else
1589 // best guess is the face color here
1590 // but it may be totally wrong. the background color
1591 // was typically already reset
1592 aCol = rStyleSettings.GetFaceColor();
1593
1594 bHighContrastBlack = aCol.IsDark();
1595 bHighContrastWhite = aCol.IsBright();
1596 }
1597
1598 aOldTextColor = rTargetDevice.GetTextColor();
1599 if ( rTargetDevice.IsTextFillColor() )
1600 {
1601 bRestoreFillColor = true;
1602 aOldTextFillColor = rTargetDevice.GetTextFillColor();
1603 }
1604 if( bHighContrastBlack )
1605 rTargetDevice.SetTextColor( COL_GREEN );
1606 else if( bHighContrastWhite )
1607 rTargetDevice.SetTextColor( COL_LIGHTGREEN );
1608 else
1609 {
1610 // draw disabled text always without shadow
1611 // as it fits better with native look
1612 rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
1613 }
1614 }
1615
1616 tools::Long nWidth = rRect.GetWidth();
1617 tools::Long nHeight = rRect.GetHeight();
1618
1619 if (nWidth <= 0 || nHeight <= 0)
1620 {
1621 if (nStyle & DrawTextFlags::Clip)
1622 return;
1623 static bool bFuzzing = utl::ConfigManager::IsFuzzing();
1624 SAL_WARN_IF(bFuzzing, "vcl", "skipping negative rectangle of: " << nWidth << " x " << nHeight);
1625 if (bFuzzing)
1626 return;
1627 }
1628
1629 Point aPos = rRect.TopLeft();
1630
1631 tools::Long nTextHeight = rTargetDevice.GetTextHeight();
1632 TextAlign eAlign = rTargetDevice.GetTextAlign();
1633 sal_Int32 nMnemonicPos = -1;
1634
1635 OUString aStr = rOrigStr;
1636 if ( nStyle & DrawTextFlags::Mnemonic )
1637 aStr = removeMnemonicFromString( aStr, nMnemonicPos );
1638
1639 const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::NoMnemonics) && !pVector;
1640
1641 // We treat multiline text differently
1642 if ( nStyle & DrawTextFlags::MultiLine )
1643 {
1644
1645 ImplMultiTextLineInfo aMultiLineInfo;
1646 sal_Int32 i;
1647 sal_Int32 nFormatLines;
1648
1649 if ( nTextHeight )
1650 {
1651 tools::Long nMaxTextWidth = ImplGetTextLines( rRect, nTextHeight, aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
1652 sal_Int32 nLines = static_cast<sal_Int32>(nHeight/nTextHeight);
1653 OUString aLastLine;
1654 nFormatLines = aMultiLineInfo.Count();
1655 if (nLines <= 0)
1656 nLines = 1;
1657 if ( nFormatLines > nLines )
1658 {
1659 if ( nStyle & DrawTextFlags::EndEllipsis )
1660 {
1661 // Create last line and shorten it
1662 nFormatLines = nLines-1;
1663
1664 ImplTextLineInfo& rLineInfo = aMultiLineInfo.GetLine( nFormatLines );
1665 aLastLine = convertLineEnd(aStr.copy(rLineInfo.GetIndex()), LINEEND_LF);
1666 // Replace all LineFeeds with Spaces
1667 OUStringBuffer aLastLineBuffer(aLastLine);
1668 sal_Int32 nLastLineLen = aLastLineBuffer.getLength();
1669 for ( i = 0; i < nLastLineLen; i++ )
1670 {
1671 if ( aLastLineBuffer[ i ] == '\n' )
1672 aLastLineBuffer[ i ] = ' ';
1673 }
1674 aLastLine = aLastLineBuffer.makeStringAndClear();
1675 aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
1677 nStyle |= DrawTextFlags::Top;
1678 }
1679 }
1680 else
1681 {
1682 if ( nMaxTextWidth <= nWidth )
1683 nStyle &= ~DrawTextFlags::Clip;
1684 }
1685
1686 // Do we need to clip the height?
1687 if ( nFormatLines*nTextHeight > nHeight )
1688 nStyle |= DrawTextFlags::Clip;
1689
1690 // Set clipping
1691 if ( nStyle & DrawTextFlags::Clip )
1692 {
1693 rTargetDevice.Push( vcl::PushFlags::CLIPREGION );
1694 rTargetDevice.IntersectClipRegion( rRect );
1695 }
1696
1697 // Vertical alignment
1698 if ( nStyle & DrawTextFlags::Bottom )
1699 aPos.AdjustY(nHeight-(nFormatLines*nTextHeight) );
1700 else if ( nStyle & DrawTextFlags::VCenter )
1701 aPos.AdjustY((nHeight-(nFormatLines*nTextHeight))/2 );
1702
1703 // Font alignment
1704 if ( eAlign == ALIGN_BOTTOM )
1705 aPos.AdjustY(nTextHeight );
1706 else if ( eAlign == ALIGN_BASELINE )
1707 aPos.AdjustY(rTargetDevice.GetFontMetric().GetAscent() );
1708
1709 // Output all lines except for the last one
1710 for ( i = 0; i < nFormatLines; i++ )
1711 {
1712 ImplTextLineInfo& rLineInfo = aMultiLineInfo.GetLine( i );
1713 if ( nStyle & DrawTextFlags::Right )
1714 aPos.AdjustX(nWidth-rLineInfo.GetWidth() );
1715 else if ( nStyle & DrawTextFlags::Center )
1716 aPos.AdjustX((nWidth-rLineInfo.GetWidth())/2 );
1717 sal_Int32 nIndex = rLineInfo.GetIndex();
1718 sal_Int32 nLineLen = rLineInfo.GetLen();
1719 _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
1720 if ( bDrawMnemonics )
1721 {
1722 if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
1723 {
1724 tools::Long nMnemonicX;
1725 tools::Long nMnemonicY;
1726 DeviceCoordinate nMnemonicWidth;
1727
1728 std::unique_ptr<sal_Int32[]> const pCaretXArray(new sal_Int32[2 * nLineLen]);
1729 /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray.get(),
1730 nIndex, nLineLen );
1731 sal_Int32 lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
1732 sal_Int32 lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
1733 nMnemonicWidth = rTargetDevice.LogicWidthToDeviceCoordinate( std::abs(lc_x1 - lc_x2) );
1734
1735 Point aTempPos = rTargetDevice.LogicToPixel( aPos );
1736 nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min( lc_x1, lc_x2 ) );
1737 nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
1738 rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
1739 }
1740 }
1741 aPos.AdjustY(nTextHeight );
1742 aPos.setX( rRect.Left() );
1743 }
1744
1745 // If there still is a last line, we output it left-aligned as the line would be clipped
1746 if ( !aLastLine.isEmpty() )
1747 _rLayout.DrawText( aPos, aLastLine, 0, aLastLine.getLength(), pVector, pDisplayText );
1748
1749 // Reset clipping
1750 if ( nStyle & DrawTextFlags::Clip )
1751 rTargetDevice.Pop();
1752 }
1753 }
1754 else
1755 {
1756 tools::Long nTextWidth = _rLayout.GetTextWidth( aStr, 0, -1 );
1757
1758 // Clip text if needed
1759 if ( nTextWidth > nWidth )
1760 {
1761 if ( nStyle & TEXT_DRAW_ELLIPSIS )
1762 {
1763 aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
1765 nStyle |= DrawTextFlags::Left;
1766 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.getLength() );
1767 }
1768 }
1769 else
1770 {
1771 if ( nTextHeight <= nHeight )
1772 nStyle &= ~DrawTextFlags::Clip;
1773 }
1774
1775 // horizontal text alignment
1776 if ( nStyle & DrawTextFlags::Right )
1777 aPos.AdjustX(nWidth-nTextWidth );
1778 else if ( nStyle & DrawTextFlags::Center )
1779 aPos.AdjustX((nWidth-nTextWidth)/2 );
1780
1781 // vertical font alignment
1782 if ( eAlign == ALIGN_BOTTOM )
1783 aPos.AdjustY(nTextHeight );
1784 else if ( eAlign == ALIGN_BASELINE )
1785 aPos.AdjustY(rTargetDevice.GetFontMetric().GetAscent() );
1786
1787 if ( nStyle & DrawTextFlags::Bottom )
1788 aPos.AdjustY(nHeight-nTextHeight );
1789 else if ( nStyle & DrawTextFlags::VCenter )
1790 aPos.AdjustY((nHeight-nTextHeight)/2 );
1791
1792 tools::Long nMnemonicX = 0;
1793 tools::Long nMnemonicY = 0;
1794 DeviceCoordinate nMnemonicWidth = 0;
1795 if (nMnemonicPos != -1 && nMnemonicPos < aStr.getLength())
1796 {
1797 std::unique_ptr<sal_Int32[]> const pCaretXArray(new sal_Int32[2 * aStr.getLength()]);
1798 /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray.get(), 0, aStr.getLength() );
1799 sal_Int32 lc_x1 = pCaretXArray[2*nMnemonicPos];
1800 sal_Int32 lc_x2 = pCaretXArray[2*nMnemonicPos+1];
1801 nMnemonicWidth = rTargetDevice.LogicWidthToDeviceCoordinate( std::abs(lc_x1 - lc_x2) );
1802
1803 Point aTempPos = rTargetDevice.LogicToPixel( aPos );
1804 nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min(lc_x1, lc_x2) );
1805 nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
1806 }
1807
1808 if ( nStyle & DrawTextFlags::Clip )
1809 {
1810 rTargetDevice.Push( vcl::PushFlags::CLIPREGION );
1811 rTargetDevice.IntersectClipRegion( rRect );
1812 _rLayout.DrawText( aPos, aStr, 0, aStr.getLength(), pVector, pDisplayText );
1813 if ( bDrawMnemonics && nMnemonicPos != -1 )
1814 rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
1815 rTargetDevice.Pop();
1816 }
1817 else
1818 {
1819 _rLayout.DrawText( aPos, aStr, 0, aStr.getLength(), pVector, pDisplayText );
1820 if ( bDrawMnemonics && nMnemonicPos != -1 )
1821 rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
1822 }
1823 }
1824
1825 if ( nStyle & DrawTextFlags::Disable && !pVector )
1826 {
1827 rTargetDevice.SetTextColor( aOldTextColor );
1828 if ( bRestoreFillColor )
1829 rTargetDevice.SetTextFillColor( aOldTextFillColor );
1830 }
1831}
1832
1834 const OUString& rOrigStr,
1835 DrawTextFlags nStyle,
1836 GDIMetaFile& rMtf )
1837{
1838
1839 if ( rOrigStr.isEmpty() || rRect.IsEmpty() )
1840 return;
1841
1842 // we need a graphics
1843 if( !mpGraphics && !AcquireGraphics() )
1844 return;
1845 assert(mpGraphics);
1846 if( mbInitClipRegion )
1848
1849 // temporarily swap in passed mtf for action generation, and
1850 // disable output generation.
1851 const bool bOutputEnabled( IsOutputEnabled() );
1852 GDIMetaFile* pMtf = mpMetaFile;
1853
1854 mpMetaFile = &rMtf;
1855 EnableOutput( false );
1856
1857 // #i47157# Factored out to ImplDrawTextRect(), to be shared
1858 // between us and DrawText()
1859 vcl::DefaultTextLayout aLayout( *this );
1860 ImplDrawText( *this, rRect, rOrigStr, nStyle, nullptr, nullptr, aLayout );
1861
1862 // and restore again
1863 EnableOutput( bOutputEnabled );
1864 mpMetaFile = pMtf;
1865}
1866
1867void OutputDevice::DrawText( const tools::Rectangle& rRect, const OUString& rOrigStr, DrawTextFlags nStyle,
1868 std::vector< tools::Rectangle >* pVector, OUString* pDisplayText,
1869 vcl::ITextLayout* _pTextLayout )
1870{
1871 assert(!is_double_buffered_window());
1872
1873 if (mpOutDevData->mpRecordLayout)
1874 {
1875 pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
1876 pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
1877 }
1878
1879 bool bDecomposeTextRectAction = ( _pTextLayout != nullptr ) && _pTextLayout->DecomposeTextRectAction();
1880 if ( mpMetaFile && !bDecomposeTextRectAction )
1881 mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
1882
1883 if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || rOrigStr.isEmpty() || rRect.IsEmpty() )
1884 return;
1885
1886 // we need a graphics
1887 if( !mpGraphics && !AcquireGraphics() )
1888 return;
1889 assert(mpGraphics);
1890 if( mbInitClipRegion )
1892 if (mbOutputClipped && !bDecomposeTextRectAction && !pDisplayText)
1893 return;
1894
1895 // temporarily disable mtf action generation (ImplDrawText _does_
1896 // create MetaActionType::TEXTs otherwise)
1897 GDIMetaFile* pMtf = mpMetaFile;
1898 if ( !bDecomposeTextRectAction )
1899 mpMetaFile = nullptr;
1900
1901 // #i47157# Factored out to ImplDrawText(), to be used also
1902 // from AddTextRectActions()
1903 vcl::DefaultTextLayout aDefaultLayout( *this );
1904 ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
1905
1906 // and enable again
1907 mpMetaFile = pMtf;
1908
1909 if( mpAlphaVDev )
1910 mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
1911}
1912
1914 const OUString& rStr, DrawTextFlags nStyle,
1915 TextRectInfo* pInfo,
1916 const vcl::ITextLayout* _pTextLayout ) const
1917{
1918
1919 tools::Rectangle aRect = rRect;
1920 sal_Int32 nLines;
1921 tools::Long nWidth = rRect.GetWidth();
1922 tools::Long nMaxWidth;
1923 tools::Long nTextHeight = GetTextHeight();
1924
1925 OUString aStr = rStr;
1926 if ( nStyle & DrawTextFlags::Mnemonic )
1928
1929 if ( nStyle & DrawTextFlags::MultiLine )
1930 {
1931 ImplMultiTextLineInfo aMultiLineInfo;
1932 sal_Int32 nFormatLines;
1933 sal_Int32 i;
1934
1935 nMaxWidth = 0;
1936 vcl::DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
1937 ImplGetTextLines( rRect, nTextHeight, aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
1938 nFormatLines = aMultiLineInfo.Count();
1939 if ( !nTextHeight )
1940 nTextHeight = 1;
1941 nLines = static_cast<sal_uInt16>(aRect.GetHeight()/nTextHeight);
1942 if ( pInfo )
1943 pInfo->mnLineCount = nFormatLines;
1944 if ( !nLines )
1945 nLines = 1;
1946 if ( nFormatLines <= nLines )
1947 nLines = nFormatLines;
1948 else
1949 {
1950 if ( !(nStyle & DrawTextFlags::EndEllipsis) )
1951 nLines = nFormatLines;
1952 else
1953 {
1954 if ( pInfo )
1955 pInfo->mbEllipsis = true;
1956 nMaxWidth = nWidth;
1957 }
1958 }
1959 if ( pInfo )
1960 {
1961 bool bMaxWidth = nMaxWidth == 0;
1962 pInfo->mnMaxWidth = 0;
1963 for ( i = 0; i < nLines; i++ )
1964 {
1965 ImplTextLineInfo& rLineInfo = aMultiLineInfo.GetLine( i );
1966 if ( bMaxWidth && (rLineInfo.GetWidth() > nMaxWidth) )
1967 nMaxWidth = rLineInfo.GetWidth();
1968 if ( rLineInfo.GetWidth() > pInfo->mnMaxWidth )
1969 pInfo->mnMaxWidth = rLineInfo.GetWidth();
1970 }
1971 }
1972 else if ( !nMaxWidth )
1973 {
1974 for ( i = 0; i < nLines; i++ )
1975 {
1976 ImplTextLineInfo& rLineInfo = aMultiLineInfo.GetLine( i );
1977 if ( rLineInfo.GetWidth() > nMaxWidth )
1978 nMaxWidth = rLineInfo.GetWidth();
1979 }
1980 }
1981 }
1982 else
1983 {
1984 nLines = 1;
1985 nMaxWidth = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.getLength() ) : GetTextWidth( aStr );
1986
1987 if ( pInfo )
1988 {
1989 pInfo->mnLineCount = 1;
1990 pInfo->mnMaxWidth = nMaxWidth;
1991 }
1992
1993 if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
1994 {
1995 if ( pInfo )
1996 pInfo->mbEllipsis = true;
1997 nMaxWidth = nWidth;
1998 }
1999 }
2000
2001 if ( nStyle & DrawTextFlags::Right )
2002 aRect.SetLeft( aRect.Right()-nMaxWidth+1 );
2003 else if ( nStyle & DrawTextFlags::Center )
2004 {
2005 aRect.AdjustLeft((nWidth-nMaxWidth)/2 );
2006 aRect.SetRight( aRect.Left()+nMaxWidth-1 );
2007 }
2008 else
2009 aRect.SetRight( aRect.Left()+nMaxWidth-1 );
2010
2011 if ( nStyle & DrawTextFlags::Bottom )
2012 aRect.SetTop( aRect.Bottom()-(nTextHeight*nLines)+1 );
2013 else if ( nStyle & DrawTextFlags::VCenter )
2014 {
2015 aRect.AdjustTop((aRect.GetHeight()-(nTextHeight*nLines))/2 );
2016 aRect.SetBottom( aRect.Top()+(nTextHeight*nLines)-1 );
2017 }
2018 else
2019 aRect.SetBottom( aRect.Top()+(nTextHeight*nLines)-1 );
2020
2021 // #99188# get rid of rounding problems when using this rect later
2022 if (nStyle & DrawTextFlags::Right)
2023 aRect.AdjustLeft( -1 );
2024 else
2025 aRect.AdjustRight( 1 );
2026
2027 if (maFont.GetOrientation() != 0_deg10)
2028 {
2029 tools::Polygon aRotatedPolygon(aRect);
2030 aRotatedPolygon.Rotate(Point(aRect.GetWidth() / 2, aRect.GetHeight() / 2), maFont.GetOrientation());
2031 return aRotatedPolygon.GetBoundRect();
2032 }
2033
2034 return aRect;
2035}
2036
2037static bool ImplIsCharIn( sal_Unicode c, const char* pStr )
2038{
2039 while ( *pStr )
2040 {
2041 if ( *pStr == c )
2042 return true;
2043 pStr++;
2044 }
2045
2046 return false;
2047}
2048
2049OUString OutputDevice::GetEllipsisString( const OUString& rOrigStr, tools::Long nMaxWidth,
2050 DrawTextFlags nStyle ) const
2051{
2052 vcl::DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
2053 return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
2054}
2055
2056OUString OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const OUString& rOrigStr, tools::Long nMaxWidth,
2057 DrawTextFlags nStyle, const vcl::ITextLayout& _rLayout )
2058{
2059 OUString aStr = rOrigStr;
2060 sal_Int32 nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.getLength() );
2061
2062 if ( nIndex != -1 )
2063 {
2065 {
2066 OUStringBuffer aTmpStr( aStr );
2067 // speed it up by removing all but 1.33x as many as the break pos.
2068 sal_Int32 nEraseChars = std::max<sal_Int32>(4, aStr.getLength() - (nIndex*4)/3);
2069 while( nEraseChars < aStr.getLength() && _rLayout.GetTextWidth( aTmpStr.toString(), 0, aTmpStr.getLength() ) > nMaxWidth )
2070 {
2071 aTmpStr = aStr;
2072 sal_Int32 i = (aTmpStr.getLength() - nEraseChars)/2;
2073 aTmpStr.remove(i, nEraseChars++);
2074 aTmpStr.insert(i, "...");
2075 }
2076 aStr = aTmpStr.makeStringAndClear();
2077 }
2078 else if ( nStyle & DrawTextFlags::EndEllipsis )
2079 {
2080 aStr = aStr.copy(0, nIndex);
2081 if ( nIndex > 1 )
2082 {
2083 aStr += "...";
2084 while ( !aStr.isEmpty() && (_rLayout.GetTextWidth( aStr, 0, aStr.getLength() ) > nMaxWidth) )
2085 {
2086 if ( (nIndex > 1) || (nIndex == aStr.getLength()) )
2087 nIndex--;
2088 aStr = aStr.replaceAt( nIndex, 1, u"");
2089 }
2090 }
2091
2092 if ( aStr.isEmpty() && (nStyle & DrawTextFlags::Clip) )
2093 aStr += OUStringChar(rOrigStr[ 0 ]);
2094 }
2095 else if ( nStyle & DrawTextFlags::PathEllipsis )
2096 {
2097 OUString aPath( rOrigStr );
2098 OUString aAbbreviatedPath;
2099 osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, nullptr );
2100 aStr = aAbbreviatedPath;
2101 }
2102 else if ( nStyle & DrawTextFlags::NewsEllipsis )
2103 {
2104 static char const pSepChars[] = ".";
2105 // Determine last section
2106 sal_Int32 nLastContent = aStr.getLength();
2107 while ( nLastContent )
2108 {
2109 nLastContent--;
2110 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
2111 break;
2112 }
2113 while ( nLastContent &&
2114 ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
2115 nLastContent--;
2116
2117 OUString aLastStr = aStr.copy(nLastContent);
2118 OUString aTempLastStr1 = "..." + aLastStr;
2119 if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.getLength() ) > nMaxWidth )
2120 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | DrawTextFlags::EndEllipsis, _rLayout );
2121 else
2122 {
2123 sal_Int32 nFirstContent = 0;
2124 while ( nFirstContent < nLastContent )
2125 {
2126 nFirstContent++;
2127 if ( ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
2128 break;
2129 }
2130 while ( (nFirstContent < nLastContent) &&
2131 ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
2132 nFirstContent++;
2133 // MEM continue here
2134 if ( nFirstContent >= nLastContent )
2135 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | DrawTextFlags::EndEllipsis, _rLayout );
2136 else
2137 {
2138 if ( nFirstContent > 4 )
2139 nFirstContent = 4;
2140 OUString aFirstStr = OUString::Concat(aStr.subView( 0, nFirstContent )) + "...";
2141 OUString aTempStr = aFirstStr + aLastStr;
2142 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
2143 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | DrawTextFlags::EndEllipsis, _rLayout );
2144 else
2145 {
2146 do
2147 {
2148 aStr = aTempStr;
2149 if( nLastContent > aStr.getLength() )
2150 nLastContent = aStr.getLength();
2151 while ( nFirstContent < nLastContent )
2152 {
2153 nLastContent--;
2154 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
2155 break;
2156
2157 }
2158 while ( (nFirstContent < nLastContent) &&
2159 ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
2160 nLastContent--;
2161
2162 if ( nFirstContent < nLastContent )
2163 {
2164 std::u16string_view aTempLastStr = aStr.subView( nLastContent );
2165 aTempStr = aFirstStr + aTempLastStr;
2166
2167 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
2168 break;
2169 }
2170 }
2171 while ( nFirstContent < nLastContent );
2172 }
2173 }
2174 }
2175 }
2176 }
2177
2178 return aStr;
2179}
2180
2181void OutputDevice::DrawCtrlText( const Point& rPos, const OUString& rStr,
2182 sal_Int32 nIndex, sal_Int32 nLen,
2183 DrawTextFlags nStyle, std::vector< tools::Rectangle >* pVector, OUString* pDisplayText,
2184 const SalLayoutGlyphs* pGlyphs )
2185{
2186 assert(!is_double_buffered_window());
2187
2188 if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
2189 {
2190 nLen = rStr.getLength() - nIndex;
2191 }
2192
2193 if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.getLength()) )
2194 return;
2195
2196 // better get graphics here because ImplDrawMnemonicLine() will not
2197 // we need a graphics
2198 if( !mpGraphics && !AcquireGraphics() )
2199 return;
2200 assert(mpGraphics);
2201 if( mbInitClipRegion )
2203 if ( mbOutputClipped )
2204 return;
2205
2206 if( nIndex >= rStr.getLength() )
2207 return;
2208
2209 if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
2210 {
2211 nLen = rStr.getLength() - nIndex;
2212 }
2213 OUString aStr = rStr;
2214 sal_Int32 nMnemonicPos = -1;
2215
2216 tools::Long nMnemonicX = 0;
2217 tools::Long nMnemonicY = 0;
2218 tools::Long nMnemonicWidth = 0;
2219 if ( (nStyle & DrawTextFlags::Mnemonic) && nLen > 1 )
2220 {
2221 aStr = removeMnemonicFromString( aStr, nMnemonicPos );
2222 if ( nMnemonicPos != -1 )
2223 {
2224 if( nMnemonicPos < nIndex )
2225 {
2226 --nIndex;
2227 }
2228 else
2229 {
2230 if( nMnemonicPos < (nIndex+nLen) )
2231 --nLen;
2232 SAL_WARN_IF( nMnemonicPos >= (nIndex+nLen), "vcl", "Mnemonic underline marker after last character" );
2233 }
2234 bool bInvalidPos = false;
2235
2236 if( nMnemonicPos >= nLen )
2237 {
2238 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
2239 // due to some strange BiDi text editors
2240 // -> place the underline behind the string to indicate a failure
2241 bInvalidPos = true;
2242 nMnemonicPos = nLen-1;
2243 }
2244
2245 std::unique_ptr<sal_Int32[]> const pCaretXArray(new sal_Int32[2 * nLen]);
2246 /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray.get(), nIndex, nLen, pGlyphs );
2247 sal_Int32 lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
2248 sal_Int32 lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
2249 nMnemonicWidth = ::abs(static_cast<int>(lc_x1 - lc_x2));
2250
2251 Point aTempPos( std::min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
2252 if( bInvalidPos ) // #106952#, place behind the (last) character
2253 aTempPos = Point( std::max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
2254
2255 aTempPos += rPos;
2256 aTempPos = LogicToPixel( aTempPos );
2257 nMnemonicX = mnOutOffX + aTempPos.X();
2258 nMnemonicY = mnOutOffY + aTempPos.Y();
2259 }
2260 }
2261
2262 bool autoacc = ImplGetSVData()->maNWFData.mbAutoAccel;
2263
2264 if ( nStyle & DrawTextFlags::Disable && ! pVector )
2265 {
2266 Color aOldTextColor;
2267 Color aOldTextFillColor;
2268 bool bRestoreFillColor;
2269 bool bHighContrastBlack = false;
2270 bool bHighContrastWhite = false;
2271 const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
2272 if( rStyleSettings.GetHighContrastMode() )
2273 {
2274 if( IsBackground() )
2275 {
2276 Wallpaper aWall = GetBackground();
2277 Color aCol = aWall.GetColor();
2278 bHighContrastBlack = aCol.IsDark();
2279 bHighContrastWhite = aCol.IsBright();
2280 }
2281 }
2282
2283 aOldTextColor = GetTextColor();
2284 if ( IsTextFillColor() )
2285 {
2286 bRestoreFillColor = true;
2287 aOldTextFillColor = GetTextFillColor();
2288 }
2289 else
2290 bRestoreFillColor = false;
2291
2292 if( bHighContrastBlack )
2294 else if( bHighContrastWhite )
2296 else
2297 SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
2298
2299 DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
2300 if (!(GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::NoMnemonics)
2301 && (!autoacc || !(nStyle & DrawTextFlags::HideMnemonic)) )
2302 {
2303 if ( nMnemonicPos != -1 )
2304 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
2305 }
2306 SetTextColor( aOldTextColor );
2307 if ( bRestoreFillColor )
2308 SetTextFillColor( aOldTextFillColor );
2309 }
2310 else
2311 {
2312 DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText, pGlyphs );
2313 if ( !(GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::NoMnemonics) && !pVector
2314 && (!autoacc || !(nStyle & DrawTextFlags::HideMnemonic)) )
2315 {
2316 if ( nMnemonicPos != -1 )
2317 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
2318 }
2319 }
2320
2321 if( mpAlphaVDev )
2322 mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
2323}
2324
2325tools::Long OutputDevice::GetCtrlTextWidth( const OUString& rStr, const SalLayoutGlyphs* pGlyphs ) const
2326{
2327 sal_Int32 nLen = rStr.getLength();
2328 sal_Int32 nIndex = 0;
2329
2330 sal_Int32 nMnemonicPos;
2331 OUString aStr = removeMnemonicFromString( rStr, nMnemonicPos );
2332 if ( nMnemonicPos != -1 )
2333 {
2334 if ( nMnemonicPos < nIndex )
2335 nIndex--;
2336 else if (static_cast<sal_uLong>(nMnemonicPos) < static_cast<sal_uLong>(nIndex+nLen))
2337 nLen--;
2338 }
2339 return GetTextWidth( aStr, nIndex, nLen, nullptr, pGlyphs );
2340}
2341
2343 const OUString& rStr, sal_Int32 nBase,
2344 sal_Int32 nIndex, sal_Int32 nLen,
2345 sal_uLong nLayoutWidth, o3tl::span<const sal_Int32> pDXAry,
2346 o3tl::span<const sal_Bool> pKashidaAry,
2347 const SalLayoutGlyphs* pGlyphs ) const
2348{
2349 bool bRet = false;
2350 rRect.SetEmpty();
2351
2352 std::unique_ptr<SalLayout> pSalLayout;
2353 const Point aPoint;
2354 // calculate offset when nBase!=nIndex
2355 tools::Long nXOffset = 0;
2356 if( nBase != nIndex )
2357 {
2358 sal_Int32 nStart = std::min( nBase, nIndex );
2359 sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart;
2360 pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry, pKashidaAry );
2361 if( pSalLayout )
2362 {
2363 nXOffset = pSalLayout->GetTextWidth();
2364 nXOffset /= pSalLayout->GetUnitsPerPixel();
2365 // TODO: fix offset calculation for Bidi case
2366 if( nBase < nIndex)
2367 nXOffset = -nXOffset;
2368 }
2369 }
2370
2371 pSalLayout = ImplLayout(rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry, pKashidaAry, eDefaultLayout,
2372 nullptr, pGlyphs);
2373 if( pSalLayout )
2374 {
2375 tools::Rectangle aPixelRect;
2376 bRet = pSalLayout->GetBoundRect(aPixelRect);
2377
2378 if( bRet )
2379 {
2380 int nWidthFactor = pSalLayout->GetUnitsPerPixel();
2381
2382 if( nWidthFactor > 1 )
2383 {
2384 double fFactor = 1.0 / nWidthFactor;
2385 aPixelRect.SetLeft(
2386 static_cast< tools::Long >(aPixelRect.Left() * fFactor) );
2387 aPixelRect.SetRight(
2388 static_cast< tools::Long >(aPixelRect.Right() * fFactor) );
2389 aPixelRect.SetTop(
2390 static_cast< tools::Long >(aPixelRect.Top() * fFactor) );
2391 aPixelRect.SetBottom(
2392 static_cast< tools::Long >(aPixelRect.Bottom() * fFactor) );
2393 }
2394
2395 Point aRotatedOfs( mnTextOffX, mnTextOffY );
2396 DevicePoint aPos = pSalLayout->GetDrawPosition(DevicePoint(nXOffset, 0));
2397 aRotatedOfs -= Point(aPos.getX(), aPos.getY());
2398 aPixelRect += aRotatedOfs;
2399 rRect = PixelToLogic( aPixelRect );
2400 if( mbMap )
2402 }
2403 }
2404
2405 return bRet;
2406}
2407
2409 const OUString& rStr, sal_Int32 nBase,
2410 sal_Int32 nIndex, sal_Int32 nLen,
2411 sal_uLong nLayoutWidth,
2413 o3tl::span<const sal_Bool> pKashidaArray ) const
2414{
2415 if (!InitFont())
2416 return false;
2417
2418 bool bRet = false;
2419 rVector.clear();
2420 if( nLen < 0 )
2421 {
2422 nLen = rStr.getLength() - nIndex;
2423 }
2424 rVector.reserve( nLen );
2425
2426 // we want to get the Rectangle in logical units, so to
2427 // avoid rounding errors we just size the font in logical units
2428 bool bOldMap = mbMap;
2429 if( bOldMap )
2430 {
2431 const_cast<OutputDevice&>(*this).mbMap = false;
2432 const_cast<OutputDevice&>(*this).mbNewFont = true;
2433 }
2434
2435 std::unique_ptr<SalLayout> pSalLayout;
2436
2437 // calculate offset when nBase!=nIndex
2438 tools::Long nXOffset = 0;
2439 if( nBase != nIndex )
2440 {
2441 sal_Int32 nStart = std::min( nBase, nIndex );
2442 sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart;
2443 pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nLayoutWidth, pDXArray, pKashidaArray);
2444 if( pSalLayout )
2445 {
2446 nXOffset = pSalLayout->GetTextWidth();
2447 pSalLayout.reset();
2448 // TODO: fix offset calculation for Bidi case
2449 if( nBase > nIndex)
2450 nXOffset = -nXOffset;
2451 }
2452 }
2453
2454 pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray, pKashidaArray );
2455 if( pSalLayout )
2456 {
2457 bRet = pSalLayout->GetOutline(rVector);
2458 if( bRet )
2459 {
2460 // transform polygon to pixel units
2461 basegfx::B2DHomMatrix aMatrix;
2462
2463 int nWidthFactor = pSalLayout->GetUnitsPerPixel();
2464 if( nXOffset | mnTextOffX | mnTextOffY )
2465 {
2466 DevicePoint aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
2467 aRotatedOfs -= pSalLayout->GetDrawPosition(DevicePoint(nXOffset, 0));
2468 aMatrix.translate( aRotatedOfs.getX(), aRotatedOfs.getY() );
2469 }
2470
2471 if( nWidthFactor > 1 )
2472 {
2473 double fFactor = 1.0 / nWidthFactor;
2474 aMatrix.scale( fFactor, fFactor );
2475 }
2476
2477 if( !aMatrix.isIdentity() )
2478 {
2479 for (auto & elem : rVector)
2480 elem.transform( aMatrix );
2481 }
2482 }
2483
2484 pSalLayout.reset();
2485 }
2486
2487 if( bOldMap )
2488 {
2489 // restore original font size and map mode
2490 const_cast<OutputDevice&>(*this).mbMap = bOldMap;
2491 const_cast<OutputDevice&>(*this).mbNewFont = true;
2492 }
2493
2494 return bRet;
2495}
2496
2498 const OUString& rStr, sal_Int32 nBase,
2499 sal_Int32 nIndex, sal_Int32 nLen,
2500 sal_uLong nLayoutWidth, o3tl::span<const sal_Int32> pDXArray,
2501 o3tl::span<const sal_Bool> pKashidaArray ) const
2502{
2503 rResultVector.clear();
2504
2505 // get the basegfx polypolygon vector
2506 basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
2507 if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
2508 nLayoutWidth, pDXArray, pKashidaArray ) )
2509 return false;
2510
2511 // convert to a tool polypolygon vector
2512 rResultVector.reserve( aB2DPolyPolyVector.size() );
2513 for (auto const& elem : aB2DPolyPolyVector)
2514 rResultVector.emplace_back(elem); // #i76339#
2515
2516 return true;
2517}
2518
2519bool OutputDevice::GetTextOutline( tools::PolyPolygon& rPolyPoly, const OUString& rStr ) const
2520{
2521 rPolyPoly.Clear();
2522
2523 // get the basegfx polypolygon vector
2524 basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
2525 if( !GetTextOutlines( aB2DPolyPolyVector, rStr, 0/*nBase*/, 0/*nIndex*/, /*nLen*/-1,
2526 /*nLayoutWidth*/0, /*pDXArray*/{} ) )
2527 return false;
2528
2529 // convert and merge into a tool polypolygon
2530 for (auto const& elem : aB2DPolyPolyVector)
2531 for(auto const& rB2DPolygon : elem)
2532 rPolyPoly.Insert(tools::Polygon(rB2DPolygon)); // #i76339#
2533
2534 return true;
2535}
2536
2538{
2539 if (nFlags & SystemTextColorFlags::Mono)
2540 {
2542 }
2543 else
2544 {
2545 if (!bEnabled)
2546 {
2547 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2548 SetTextColor(rStyleSettings.GetDisableColor());
2549 }
2550 }
2551}
2552
2553/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
DrawTextFlags
sal_Int32 nLineWidth
SalLayoutFlags
SystemTextColorFlags
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:761
bool Rotate(Degree10 nAngle10, const Color &rFillColor)
Rotate bitmap by the specified angle.
bool IsEmpty() const
bool IsBright() const
bool IsDark() const
const OUString & GetFamilyName() const
const OUString & GetStyleName() const
tools::Long GetAscent() const
Definition: metric.hxx:43
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:581
sal_Int32 Count() const
void AddLine(const ImplTextLineInfo &)
Definition: text.cxx:90
std::vector< ImplTextLineInfo > mvLines
const ImplTextLineInfo & GetLine(sal_Int32 nLine) const
sal_Int32 GetIndex() const
sal_Int32 GetLen() const
tools::Long GetWidth() const
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:171
tools::Long mnEmphasisAscent
Definition: outdev.hxx:219
ImplMapRes maMapRes
Definition: outdev.hxx:223
bool ImplDrawRotateText(SalLayout &)
Definition: text.cxx:228
virtual void InitClipRegion()
void ImplDrawTextLines(SalLayout &, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bWordLine, bool bUnderlineAbove)
Definition: textline.cxx:809
tools::Long GetCtrlTextWidth(const OUString &rStr, const SalLayoutGlyphs *pLayoutCache=nullptr) const
Definition: text.cxx:2325
float approximate_digit_width() const
Definition: text.cxx:918
std::vector< FontMappingUseItem > FontMappingUseData
Definition: outdev.hxx:1264
bool GetGlyphBoundRects(const Point &rOrigin, const OUString &rStr, int nIndex, int nLen, std::vector< tools::Rectangle > &rVector) const
SAL_DLLPRIVATE std::unique_ptr< SalLayout > ImplGlyphFallbackLayout(std::unique_ptr< SalLayout >, vcl::text::ImplLayoutArgs &, const SalLayoutGlyphs *) const
static FontMappingUseData FinishTrackingFontMappingUse()
Definition: text.cxx:1307
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:646
void DrawCtrlText(const Point &rPos, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, DrawTextFlags nStyle=DrawTextFlags::Mnemonic, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr)
Definition: text.cxx:2181
tools::Long GetOutOffYPixel() const
Definition: outdev.hxx:320
const vcl::Font & GetFont() const
Definition: outdev.hxx:530
sal_Int32 GetTextBreak(const OUString &rStr, tools::Long nTextWidth, sal_Int32 nIndex, sal_Int32 nLen=-1, tools::Long nCharExtra=0, vcl::text::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1482
SAL_DLLPRIVATE bool is_double_buffered_window() const
tools::Long mnTextOffY
Definition: outdev.hxx:218
tools::Long mnOutOffY
Output offset for device output in pixel (pseudo window offset within window system's frames)
Definition: outdev.hxx:210
void EnableOutput(bool bEnable=true)
Definition: outdev.cxx:342
SAL_DLLPRIVATE tools::Long ImplDevicePixelToLogicHeight(tools::Long nHeight) const
Convert device pixels to a height in logical units.
Definition: map.cxx:361
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), tools::Long nLogicWidth=0, o3tl::span< const sal_Int32 > pLogicDXArray={}, o3tl::span< const sal_Bool > pKashidaArray={}, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::text::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1317
bool mbOutputClipped
Definition: outdev.hxx:246
void SetFont(const vcl::Font &rNewFont)
Definition: outdev/font.cxx:56
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:391
bool GetTextOutline(tools::PolyPolygon &, const OUString &rStr) const
Definition: text.cxx:2519
SAL_DLLPRIVATE void ImplDrawPolygon(const tools::Polygon &rPoly, const tools::PolyPolygon *pClipPolyPoly=nullptr)
Definition: polygon.cxx:445
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, o3tl::span< const sal_Int32 > pDXArray={}, o3tl::span< const sal_Bool > pKashidaArray={}, const SalLayoutGlyphs *pGlyphs=nullptr) const
Return the exact bounding rectangle of rStr.
Definition: text.cxx:2342
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
tools::Long mnOutOffX
Output offset for device output in pixel (pseudo window offset within window system's frames)
Definition: outdev.hxx:208
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1169
std::unique_ptr< ImplOutDevData > mpOutDevData
Definition: outdev.hxx:190
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:186
const Wallpaper & GetBackground() const
Definition: outdev.hxx:524
virtual void SetSystemTextColor(SystemTextColorFlags nFlags, bool bEnabled)
Definition: text.cxx:2537
bool mbMap
Definition: outdev.hxx:241
static SAL_DLLPRIVATE sal_Int32 ImplBreakLinesSimple(const tools::Long nWidth, const OUString &rStr, const vcl::ITextLayout &_rLayout, const sal_Int32 nPos, sal_Int32 nBreakPos, tools::Long &nLineWidth)
Definition: text.cxx:689
vcl::text::ComplexTextLayoutFlags mnTextLayoutMode
Definition: outdev.hxx:222
OUString GetEllipsisString(const OUString &rStr, tools::Long nMaxWidth, DrawTextFlags nStyle=DrawTextFlags::EndEllipsis) const
Definition: text.cxx:2049
bool mbNewFont
Definition: outdev.hxx:255
SAL_DLLPRIVATE tools::Long ImplLogicWidthToDevicePixel(tools::Long nWidth) const
Convert a logical width to a width in units of device pixels.
Definition: map.cxx:337
const Color & GetOverlineColor() const
Definition: outdev.hxx:1018
tools::Long mnEmphasisDescent
Definition: outdev.hxx:220
SAL_DLLPRIVATE SalLayoutFlags GetBiDiLayoutFlags(std::u16string_view rStr, const sal_Int32 nMinIndex, const sal_Int32 nEndIndex) const
Definition: text.cxx:1236
bool mbInitLineColor
Definition: outdev.hxx:249
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
Width of the text.
Definition: text.cxx:886
bool mbTextSpecial
Definition: outdev.hxx:257
tools::Long mnOutWidth
Definition: outdev.hxx:211
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:183
bool mbInitTextColor
Definition: outdev.hxx:252
void AddTextRectActions(const tools::Rectangle &rRect, const OUString &rOrigStr, DrawTextFlags nStyle, GDIMetaFile &rMtf)
Generate MetaTextActions for the text rect.
Definition: text.cxx:1833
void SetTextColor(const Color &rColor)
Definition: text.cxx:716
vcl::Font maFont
Definition: outdev.hxx:229
static SAL_DLLPRIVATE sal_Int32 ImplBreakLinesWithIterator(const tools::Long nWidth, const OUString &rStr, const vcl::ITextLayout &_rLayout, const css::uno::Reference< css::linguistic2::XHyphenator > &xHyph, const css::uno::Reference< css::i18n::XBreakIterator > &xBI, const bool bHyphenate, const sal_Int32 nPos, sal_Int32 nBreakPos)
Definition: text.cxx:573
void DrawMask(const Point &rDestPt, const Bitmap &rBitmap, const Color &rMaskColor)
Definition: mask.cxx:30
tools::Rectangle ImplGetTextBoundRect(const SalLayout &) const
Definition: text.cxx:190
rtl::Reference< LogicalFontInstance > mpFontInstance
Definition: outdev.hxx:187
static SAL_DLLPRIVATE OUString ImplGetEllipsisString(const OutputDevice &rTargetDevice, const OUString &rStr, tools::Long nMaxWidth, DrawTextFlags nStyle, const vcl::ITextLayout &_rLayout)
Definition: text.cxx:2056
SAL_DLLPRIVATE void ImplDrawEmphasisMarks(SalLayout &)
bool mbInitClipRegion
Definition: outdev.hxx:253
LanguageType meTextLanguage
Definition: outdev.hxx:239
SAL_DLLPRIVATE double ImplLogicWidthToDeviceSubPixel(tools::Long nWidth) const
Definition: map.cxx:1908
bool IsRTLEnabled() const
Definition: outdev.hxx:1270
void SetDigitLanguage(LanguageType)
Definition: text.cxx:71
SAL_DLLPRIVATE float approximate_char_width() const
Definition: text.cxx:910
void DrawStretchText(const Point &rStartPt, sal_uLong nWidth, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1)
Definition: text.cxx:1128
SAL_DLLPRIVATE DeviceCoordinate LogicWidthToDeviceCoordinate(tools::Long nWidth) const
Definition: map.cxx:1896
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:938
tools::Rectangle GetTextRect(const tools::Rectangle &rRect, const OUString &rStr, DrawTextFlags nStyle=DrawTextFlags::WordBreak, TextRectInfo *pInfo=nullptr, const vcl::ITextLayout *_pTextLayout=nullptr) const
Definition: text.cxx:1913
SAL_DLLPRIVATE tools::Long ImplDevicePixelToLogicWidth(tools::Long nWidth) const
Convert device pixels to a width in logical units.
Definition: map.cxx:353
TextAlign GetTextAlign() const
Definition: outdev.hxx:1022
bool IsTextFillColor() const
Definition: outdev.hxx:1009
SAL_DLLPRIVATE void ImplDrawSpecialText(SalLayout &)
Definition: text.cxx:344
FontMetric GetFontMetric() const
virtual bool HasMirroredGraphics() const
Definition: outdev.cxx:704
SAL_DLLPRIVATE DevicePoint ImplLogicToDeviceSubPixel(const Point &rLogicPt) const
Definition: map.cxx:1926
static SAL_DLLPRIVATE tools::Long ImplGetTextLines(const tools::Rectangle &rRect, tools::Long nTextHeight, ImplMultiTextLineInfo &rLineInfo, tools::Long nWidth, const OUString &rStr, DrawTextFlags nStyle, const vcl::ITextLayout &_rLayout)
Definition: text.cxx:485
bool mbTextLines
Definition: outdev.hxx:256
virtual Bitmap GetBitmap(const Point &rSrcPt, const Size &rSize) const
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:482
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:197
static void StartTrackingFontMappingUse()
Definition: text.cxx:1301
const Color & GetTextColor() const
Definition: outdev.hxx:1004
void SetTextFillColor()
Definition: text.cxx:734
void ImplDrawTextBackground(const SalLayout &)
Definition: text.cxx:170
virtual vcl::Region GetOutputBoundsClipRegion() const
Definition: text.cxx:790
static void ImplDrawText(OutputDevice &rTargetDevice, const tools::Rectangle &rRect, const OUString &rOrigStr, DrawTextFlags nStyle, std::vector< tools::Rectangle > *pVector, OUString *pDisplayText, vcl::ITextLayout &_rLayout)
Definition: text.cxx:1569
bool IsBackground() const
Definition: outdev.hxx:527
void GetCaretPositions(const OUString &, sal_Int32 *pCaretXArray, sal_Int32 nIndex, sal_Int32 nLen, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1070
bool GetTextIsRTL(const OUString &, sal_Int32 nIndex, sal_Int32 nLen) const
Definition: text.cxx:1471
bool GetTextOutlines(PolyPolyVector &, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, o3tl::span< const sal_Int32 > pDXArray={}, o3tl::span< const sal_Bool > pKashidaArray={}) const
Definition: text.cxx:2497
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
Definition: stack.cxx:33
void DrawTextArray(const Point &rStartPt, const OUString &rStr, o3tl::span< const sal_Int32 > pDXAry, o3tl::span< const sal_Bool > pKashidaAry={}, sal_Int32 nIndex=0, sal_Int32 nLen=-1, SalLayoutFlags flags=SalLayoutFlags::NONE, const SalLayoutGlyphs *pLayoutCache=nullptr)
Definition: text.cxx:923
SAL_DLLPRIVATE vcl::text::ImplLayoutArgs ImplPrepareLayoutArgs(OUString &, const sal_Int32 nIndex, const sal_Int32 nLen, DeviceCoordinate nPixelWidth, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::text::TextLayoutCache const *=nullptr) const
Definition: text.cxx:1155
SAL_DLLPRIVATE void ImplInitTextColor()
Definition: text.cxx:100
tools::Long GetTextHeight() const
Height where any character of the current font fits; in logic coordinates.
Definition: text.cxx:897
void Pop()
Definition: stack.cxx:92
bool IsOutputEnabled() const
Definition: outdev.hxx:481
tools::Long mnTextOffX
font specific text alignment offsets in pixel units
Definition: outdev.hxx:217
SAL_DLLPRIVATE void ImplDrawTextRect(tools::Long nBaseX, tools::Long nBaseY, tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight)
Definition: text.cxx:111
Color GetTextFillColor() const
Definition: text.cxx:766
SAL_DLLPRIVATE void ImplDrawTextDirect(SalLayout &, bool bTextLines)
Definition: text.cxx:301
tools::Long GetOutOffXPixel() const
Definition: outdev.hxx:319
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
Definition: text.cxx:797
void SetLayoutMode(vcl::text::ComplexTextLayoutFlags nTextLayoutMode)
Definition: text.cxx:60
void SetOverlineColor()
Definition: textline.cxx:908
const AllSettings & GetSettings() const
Definition: outdev.hxx:289
bool mbLineColor
Definition: outdev.hxx:247
static std::shared_ptr< const vcl::text::TextLayoutCache > CreateTextLayoutCache(OUString const &)
Definition: text.cxx:1465
void IntersectClipRegion(const tools::Rectangle &rRect)
SAL_DLLPRIVATE void ImplDrawMnemonicLine(tools::Long nX, tools::Long nY, tools::Long nWidth)
Definition: textline.cxx:869
tools::Long GetTextArray(const OUString &rStr, std::vector< sal_Int32 > *pDXAry, sal_Int32 nIndex=0, sal_Int32 nLen=-1, bool bCaret=false, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
Definition: text.cxx:958
const Color & GetTextLineColor() const
Definition: outdev.hxx:1013
void SetTextLineColor()
Definition: textline.cxx:883
SAL_DLLPRIVATE bool InitFont() const
sal_Int32 mnDPIX
Definition: outdev.hxx:213
bool mbInitFillColor
Definition: outdev.hxx:250
virtual bool IsVirtual() const
Definition: outdev.cxx:186
const OutDevType meOutDevType
Definition: outdev.hxx:224
virtual void SetTextColor(Color nColor)=0
virtual void SetLineColor()=0
virtual void SetFillColor()=0
virtual tools::Long GetGraphicsWidth() const =0
void DrawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, const OutputDevice &rOutDev)
virtual std::unique_ptr< GenericSalLayout > GetTextLayout(int nFallbackLevel)=0
SalLayoutFlags GetFlags() const
SalLayoutGlyphsImpl * Impl(unsigned int nLevel) const
bool IsValid() const
bool GetBoundRect(tools::Rectangle &) const
Definition: sallayout.cxx:227
DevicePoint GetDrawPosition(const DevicePoint &rRelative=DevicePoint(0, 0)) const
Definition: sallayout.cxx:154
Point & DrawOffset()
Definition: vcllayout.hxx:74
int GetUnitsPerPixel() const
Definition: vcllayout.hxx:83
DevicePoint & DrawBase()
Definition: vcllayout.hxx:72
virtual DeviceCoordinate GetTextWidth() const
Definition: vcllayout.hxx:99
virtual void DrawText(SalGraphics &) const =0
virtual SalLayoutGlyphs GetGlyphs() const
Definition: sallayout.cxx:263
bool GetHighContrastMode() const
StyleSettingsOptions GetOptions() const
const Color & GetFaceColor() const
const Color & GetDisableColor() const
sal_uInt16 mnLineCount
tools::Long mnMaxWidth
static VclPtr< reference_type > Create(Arg &&... arg)
A construction helper for VclPtr.
Definition: vclptr.hxx:127
bool SetOutputSizePixel(const Size &rNewSize, bool bErase=true)
Definition: virdev.cxx:406
const Color & GetColor() const
Definition: wall.hxx:71
void translate(double fX, double fY)
void scale(double fX, double fY)
bool isIdentity() const
void adjustY(TYPE fY)
TYPE getX() const
void adjustX(TYPE fX)
TYPE getY() const
void setX(TYPE fX)
constexpr pointer data() const noexcept
constexpr bool empty() const noexcept
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
tools::Rectangle GetBoundRect() const
void Rotate(const Point &rCenter, double fSin, double fCos)
constexpr tools::Long GetWidth() const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr void SetRight(tools::Long v)
constexpr Size GetSize() const
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr void SetBottom(tools::Long v)
constexpr tools::Long GetHeight() const
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
static bool IsFuzzing()
is an implementation of the ITextLayout interface which simply delegates its calls to the respective ...
Definition: textlayout.hxx:47
FontKerning GetKerning() const
Definition: font/font.cxx:946
void SetFontSize(const Size &)
Definition: font/font.cxx:149
void SetOrientation(Degree10 nLineOrientation)
Definition: font/font.cxx:227
const LanguageTag & GetLanguageTag() const
Definition: font/font.cxx:939
bool IsKerning() const
Definition: font/font.cxx:245
const OUString & GetStyleName() const
Definition: font/font.cxx:929
FontStrikeout GetStrikeout() const
Definition: font/font.cxx:970
bool IsShadow() const
Definition: font/font.cxx:966
FontLineStyle GetOverline() const
Definition: font/font.cxx:969
FontRelief GetRelief() const
Definition: font/font.cxx:967
FontEmphasisMark GetEmphasisMark() const
Definition: font/font.cxx:971
const OUString & GetFamilyName() const
Definition: font/font.cxx:928
bool IsUnderlineAbove() const
FontLineStyle GetUnderline() const
Definition: font/font.cxx:968
bool IsVertical() const
Definition: font/font.cxx:945
bool IsFixKerning() const
Definition: font/font.cxx:261
bool IsOutline() const
Definition: font/font.cxx:965
bool IsWordLineMode() const
Definition: font/font.cxx:972
Degree10 GetOrientation() const
Definition: font/font.cxx:944
virtual bool DecomposeTextRectAction() const =0
virtual void DrawText(const Point &_rStartPoint, const OUString &_rText, sal_Int32 _nStartIndex, sal_Int32 _nLength, std::vector< tools::Rectangle > *_pVector, OUString *_pDisplayText)=0
virtual tools::Long GetTextWidth(const OUString &_rText, sal_Int32 _nStartIndex, sal_Int32 _nLength) const =0
virtual sal_Int32 GetTextBreak(const OUString &_rText, tools::Long _nMaxTextWidth, sal_Int32 _nStartIndex, sal_Int32 _nLength) const =0
virtual void GetCaretPositions(const OUString &_rText, sal_Int32 *_pCaretXArray, sal_Int32 _nStartIndex, sal_Int32 _nLength) const =0
bool IsNull() const
Definition: region.hxx:99
void Intersect(const tools::Rectangle &rRegion)
Definition: region.cxx:583
bool Overlaps(const tools::Rectangle &rRect) const
Definition: region.cxx:1372
abstract base class for physical font faces
bool GetNextPos(int *nCharPos, bool *bRTL)
void SetOrientation(Degree10 nOrientation)
void SetKashidaArray(const sal_Bool *pKashidaArray)
void SetLayoutWidth(DeviceCoordinate nWidth)
void SetNaturalDXArray(const double *pDXArray)
static std::shared_ptr< const vcl::text::TextLayoutCache > Create(OUString const &)
constexpr ::Color COL_GREEN(0x00, 0x80, 0x00)
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_LIGHTGRAY(0xC0, 0xC0, 0xC0)
constexpr ::Color COL_LIGHTGREEN(0x00, 0xFF, 0x00)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
#define DBG_TESTSOLARMUTEX()
sal_Int32 DeviceCoordinate
basegfx::B2DPoint DevicePoint
float u
float x
FontRelief
Definition: fntstyle.hxx:26
PITCH_FIXED
ALIGN_BOTTOM
ALIGN_BASELINE
const char * name
sal_Int32 nIndex
LINEEND_LF
TOOLS_DLLPUBLIC OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
aStr
::std::vector< B2DPolyPolygon > B2DPolyPolygonVector
B2IRange fround(const B2DRange &rRange)
const LanguageTag & getLocale()
Reference< XComponentContext > getProcessComponentContext()
int i
TextAlign
long Long
ComplexTextLayoutFlags
Definition: State.hxx:76
VCL_DLLPUBLIC css::uno::Reference< css::i18n::XBreakIterator > CreateBreakIterator()
Definition: unohelp.cxx:37
sal_Int32 w
@ OUTDEV_PDF
Definition: outdev.hxx:144
std::vector< tools::PolyPolygon > PolyPolyVector
sal_UCS4 GetLocalizedChar(sal_UCS4 nChar, LanguageType eLang)
Definition: sallayout.cxx:60
sal_uIntPtr sal_uLong
tools::Long mnMapOfsY
Offset in Y direction.
Definition: ImplMapRes.hxx:29
tools::Long mnMapOfsX
Offset in X direction.
Definition: ImplMapRes.hxx:28
ImplSVNWFData maNWFData
Definition: svdata.hxx:406
bool mbAutoAccel
Definition: svdata.hxx:342
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
OUString removeMnemonicFromString(OUString const &rStr)
static OutputDevice::FontMappingUseData * fontMappingUseData
Definition: text.cxx:1266
#define TEXT_DRAW_ELLIPSIS
Definition: text.cxx:58
static bool ImplIsCharIn(sal_Unicode c, const char *pStr)
Definition: text.cxx:2037
static void TrackFontMappingUse(const vcl::Font &originalFont, const SalLayout *salLayout)
Definition: text.cxx:1273
static bool IsTrackingFontMappingUse()
Definition: text.cxx:1268
const SalLayoutFlags eDefaultLayout
Definition: text.cxx:795
sal_uInt16 sal_Unicode
sal_uInt32 sal_UCS4
Definition: vclenum.hxx:172