LibreOffice Module sw (master) 1
itrpaint.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 <hintids.hxx>
21#include <viewopt.hxx>
22#include <tools/multisel.hxx>
23#include <editeng/udlnitem.hxx>
24#include <pagefrm.hxx>
25#include <tgrditem.hxx>
26
29
30#include <viewsh.hxx>
31#include "itrpaint.hxx"
32#include <txtfrm.hxx>
33#include <swfont.hxx>
34#include "txtpaint.hxx"
35#include "porfld.hxx"
36#include "portab.hxx"
37#include <txatbase.hxx>
38#include <charfmt.hxx>
39#include "redlnitr.hxx"
40#include "porrst.hxx"
41#include "pormulti.hxx"
42#include <doc.hxx>
43
44// Returns, if we have an underline breaking situation
45// Adding some more conditions here means you also have to change them
46// in SwTextPainter::CheckSpecialUnderline
47bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
48{
49 return LINESTYLE_NONE == rFnt.GetUnderline() ||
50 rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
51 rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
52 rPor.IsHolePortion() ||
53 ( rPor.IsMultiPortion() && ! static_cast<const SwMultiPortion&>(rPor).IsBidi() ) ||
54 rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
55 SvxCaseMap::SmallCaps == rFnt.GetCaseMap();
56}
57
58static Color GetUnderColor( const SwFont *pFont )
59{
60 return pFont->GetUnderColor() == COL_AUTO ?
61 pFont->GetColor() : pFont->GetUnderColor();
62}
63
65{
66 CtorInitTextCursor( pNewFrame, pNewInf );
67 m_pInf = pNewInf;
68 SwFont *pMyFnt = GetFnt();
69 GetInfo().SetFont( pMyFnt );
70 m_bPaintDrop = false;
71}
72
74{
76 GetInfo().SetPaintOfst( 0 );
77 SwTwips nPaintOfst = rPaint.Left();
78
79 // nPaintOfst was exactly set to the end, therefore <=
80 // nPaintOfst is document global, therefore add up nLeftMar
81 // const sal_uInt16 nLeftMar = sal_uInt16(GetLeftMargin());
82 // 8310: paint of LineBreaks in empty lines.
83 if( nPaintOfst && m_pCurr->Width() )
84 {
85 SwLinePortion *pLast = nullptr;
86 // 7529 and 4757: not <= nPaintOfst
87 while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
88 < nPaintOfst )
89 {
90 if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
91 {
92 tools::Long nTmp = GetInfo().X() +pPor->Width() +
93 pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
94 if( nTmp + (pPor->Height()/2) >= nPaintOfst )
95 break;
96 GetInfo().X( nTmp );
97 GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
98 }
99 else
100 pPor->Move( GetInfo() );
101 pLast = pPor;
102 pPor = pPor->GetNextPortion();
103 }
104
105 // 7529: if PostIts return also pLast.
106 if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
107 {
108 pPor = pLast;
109 GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
110 }
111 }
112 return pPor;
113}
114
115// There are two possibilities to output transparent font:
116// 1) DrawRect on the whole line and DrawText afterwards
117// (objectively fast, subjectively slow)
118// 2) For every portion a DrawRect with subsequent DrawText is done
119// (objectively slow, subjectively fast)
120// Since the user usually judges subjectively the second method is set as default.
122 const bool bUnderSized,
123 ::std::optional<SwTaggedPDFHelper> & roTaggedLabel,
124 ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph,
125 bool const isPDFTaggingEnabled)
126{
127#if OSL_DEBUG_LEVEL > 1
128// sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
129// sal_uInt16 nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
130#endif
131
132 // maybe catch-up adjustment
133 GetAdjusted();
139 // The size of the frame
140 GetInfo().SetIdx( GetStart() );
142
143 const bool bDrawInWindow = GetInfo().OnWin();
144
145 // 6882: blank lines can't be optimized by removing them if Formatting Marks are shown
146 const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetText().isEmpty();
147
148 SwLinePortion *pPor = bEndPor ? m_pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
149
150 // Optimization!
151 SwTwips nMaxRight = std::min<SwTwips>( rPaint.Right(), Right() );
152 const SwTwips nTmpLeft = GetInfo().X();
153 //compatibility setting: allow tabstop text to exceed right margin
154 if (GetInfo().GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_OVER_MARGIN))
155 {
156 SwLinePortion* pPorIter = pPor;
157 while( pPorIter )
158 {
159 if( pPorIter->InTabGrp() )
160 {
161 const SwTabPortion* pTabPor = static_cast<SwTabPortion*>(pPorIter);
162 const SwTwips nTabPos = nTmpLeft + pTabPor->GetTabPos();
163 if( nMaxRight < nTabPos )
164 {
165 nMaxRight = rPaint.Right();
166 break;
167 }
168 }
169 pPorIter = pPorIter->GetNextPortion();
170 }
171 }
172 if( !bEndPor && nTmpLeft >= nMaxRight )
173 return;
174
175 // DropCaps!
176 // 7538: of course for the printer, too
177 if( !m_bPaintDrop )
178 {
179 // 8084: Optimization, less painting
180 // AMA: By 8084 7538 has been revived
181 // bDrawInWindow removed, so that DropCaps also can be printed
183 && GetDropLines() >= GetLineNr();
184 }
185
186 SwTwips nTmpHeight, nTmpAscent;
187 CalcAscentAndHeight( nTmpAscent, nTmpHeight );
188
189 // bClip decides if there's a need to clip
190 // The whole thing must be done before retouching
191
192 bool bClip = ( bDrawInWindow || bUnderSized ) && !rClip.IsChg();
193 if( bClip && pPor )
194 {
195 // If TopLeft or BottomLeft of the line are outside, the we must clip.
196 // The check for Right() is done in the output loop ...
197
198 if( GetInfo().GetPos().X() < rPaint.Left() ||
199 GetInfo().GetPos().Y() < rPaint.Top() ||
200 GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
201 {
202 bClip = false;
203 rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
204 }
205#if OSL_DEBUG_LEVEL > 1
206 static bool bClipAlways = false;
207 if( bClip && bClipAlways )
208 { bClip = false;
209 rClip.ChgClip( rPaint );
210 }
211#endif
212 }
213
214 // Alignment
216 Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
217 if ( aPnt1.X() < rPaint.Left() )
218 aPnt1.setX( rPaint.Left() );
219 if ( aPnt1.Y() < rPaint.Top() )
220 aPnt1.setY( rPaint.Top() );
221 Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
222 GetInfo().GetPos().Y() + nTmpHeight );
223 if ( aPnt2.X() > rPaint.Right() )
224 aPnt2.setX( rPaint.Right() );
225 if ( aPnt2.Y() > rPaint.Bottom() )
226 aPnt2.setY( rPaint.Bottom() );
227
228 const SwRect aLineRect( aPnt1, aPnt2 );
229
230 if( m_pCurr->IsClipping() )
231 {
232 const SwTextFrame& rFrame = *GetInfo().GetTextFrame();
233 // tdf#117448 at small fixed line height, enlarge clipping area in table cells
234 // to show previously clipped text content on the area of paragraph margins
235 if ( rFrame.IsInTab() )
236 rClip.ChgClip( aLineRect, m_pFrame, false, rFrame.GetTopMargin(), rFrame.GetBottomMargin() );
237 else
238 rClip.ChgClip( aLineRect, m_pFrame );
239 bClip = false;
240 }
241
242 if( !pPor && !bEndPor )
243 return;
244
245 // Baseline output also if non-TextPortion (compare TabPor with Fill)
246 // if no special vertical alignment is used,
247 // we calculate Y value for the whole line
248 SwTextGridItem const*const pGrid(GetGridItem(GetTextFrame()->FindPageFrame()));
249 const bool bAdjustBaseLine =
250 GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) ||
251 ( nullptr != pGrid ) || m_pCurr->GetHangingBaseline();
252 const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
253 if ( ! bAdjustBaseLine )
254 GetInfo().Y( nLineBaseLine );
255
256 // 7529: Pre-paint post-its
257 if( GetInfo().OnWin() && pPor && !pPor->Width() )
258 {
259 SeekAndChg( GetInfo() );
260
261 if( bAdjustBaseLine )
262 {
263 const SwTwips nOldY = GetInfo().Y();
264
265 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, nullptr,
266 GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
267 GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
268 ) );
269
270 pPor->PrePaint( GetInfo(), pPor );
271 GetInfo().Y( nOldY );
272 }
273 else
274 pPor->PrePaint( GetInfo(), pPor );
275 }
276
277 // 7923: EndPortions output chars, too, that's why we change the font
278 if( bEndPor )
280
281 const bool bRest = m_pCurr->IsRest();
282 bool bFirst = true;
283
284 SwArrowPortion *pArrow = nullptr;
285 // Reference portion for the paragraph end portion
286 SwLinePortion* pEndTempl = m_pCurr->GetFirstPortion();
287
288 while( pPor )
289 {
290 bool bSeeked = true;
291 GetInfo().SetLen( pPor->GetLen() );
292
293 const SwTwips nOldY = GetInfo().Y();
294
295 if ( bAdjustBaseLine )
296 {
297 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, pPor ) );
298
299 // we store the last portion, because a possible paragraph
300 // end character has the same font as this portion
301 // (only in special vertical alignment case, otherwise the first
302 // portion of the line is used)
303 if ( pPor->Width() && pPor->InTextGrp() )
304 pEndTempl = pPor;
305 }
306
307 // set redlining for line break symbol
308 if ( pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() && GetRedln() )
309 {
310 SeekAndChg( GetInfo() );
311 if ( m_pCurr->GetRedlineEndType() != RedlineType::None )
312 static_cast<SwBreakPortion&>(*pPor).SetRedline( m_pCurr->GetRedlineEndType() );
313 }
314
315 // A special case are GluePortions which output blanks.
316
317 // 6168: Avoid that the rest of a FieldPortion gets the attributes of the
318 // next portion with SeekAndChgBefore():
319 if( bRest && pPor->InFieldGrp() && !pPor->GetLen() )
321 else if ( pPor->IsQuoVadisPortion() )
322 {
323 // A remark on QuoVadis/ErgoSum:
324 // We use the Font set for the Paragraph for these portions.
325 // Thus, we initialize:
326 TextFrameIndex nOffset = GetInfo().GetIdx();
327 SeekStartAndChg( GetInfo(), true );
328 if( GetRedln() && m_pCurr->HasRedline() )
329 {
330 std::pair<SwTextNode const*, sal_Int32> const pos(
331 GetTextFrame()->MapViewToModel(nOffset));
332 GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
333 }
334 }
335 else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
336 SeekAndChg( GetInfo() );
337 else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
338 {
339 // Paragraph symbols should have the same font as the paragraph in front of them,
340 // except for the case that there's redlining in the paragraph
341 if( GetRedln() )
342 SeekAndChg( GetInfo() );
343 else
345 }
346 else
347 bSeeked = false;
348
349 // bRest = false;
350
351 // If the end of the portion juts out, it is clipped.
352 // A safety distance of half the height is added, so that
353 // TTF-"f" isn't overlapping into the page margin.
354 if( bClip &&
355 GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
356 {
357 bClip = false;
358 rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
359 }
360
361 // Portions, which lay "below" the text like post-its
362 SwLinePortion *pNext = pPor->GetNextPortion();
363 if( GetInfo().OnWin() && pNext && !pNext->Width() )
364 {
365 // Fix 11289: Fields were omitted here because of Last!=Owner during
366 // loading Brief.sdw. Now the fields are allowed again,
367 // by bSeeked Last!=Owner is being avoided.
368 if ( !bSeeked )
369 SeekAndChg( GetInfo() );
370 pNext->PrePaint( GetInfo(), pPor );
371 }
372
373 // We calculate a separate font for underlining.
374 CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
375 SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
376 if ( pUnderLineFnt )
377 {
378 const Point aTmpPoint( GetInfo().X(),
379 bAdjustBaseLine ?
380 pUnderLineFnt->GetPos().Y() :
381 nLineBaseLine );
382 pUnderLineFnt->SetPos( aTmpPoint );
383 }
384
385 // in extended input mode we do not want a common underline font.
386 SwUnderlineFont* pOldUnderLineFnt = nullptr;
387 if ( GetRedln() && GetRedln()->ExtOn() )
388 {
389 pOldUnderLineFnt = GetInfo().GetUnderFnt();
390 GetInfo().SetUnderFnt( nullptr );
391 }
392
393 // multiple numbering portions are possible :(
394 if (pPor->InNumberGrp() // also footnote label
395 && !static_cast<SwNumberPortion const*>(pPor)->IsFollow())
396 {
397 assert(!roTaggedLabel);
398 assert(isPDFTaggingEnabled); (void) isPDFTaggingEnabled;
399 Por_Info aPorInfo(*pPor, *this, true); // open Lbl
400 roTaggedLabel.emplace(nullptr, nullptr, &aPorInfo, *pOut);
401 }
402
403 {
404 // #i16816# tagged pdf support
405 Por_Info aPorInfo(*pPor, *this, false);
406 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut );
407
408 if( pPor->IsMultiPortion() )
409 PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) );
410 else
411 pPor->Paint( GetInfo() );
412 }
413
414 // lazy open LBody and paragraph tag after num portions have been painted to Lbl
415 if (pPor->InNumberGrp() // also footnote label
416 // note: numbering portion may be split if it has multiple scripts
417 && !static_cast<SwNumberPortion const*>(pPor)->HasFollow()) // so wait for the last one
418 {
419 assert(roTaggedLabel);
420 roTaggedLabel.reset(); // close Lbl
421 assert(!roTaggedParagraph);
422 Frame_Info aFrameInfo(*m_pFrame); // open LBody
423 roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *pOut);
424 }
425
426 // reset underline font
427 if ( pOldUnderLineFnt )
428 GetInfo().SetUnderFnt( pOldUnderLineFnt );
429
430 // reset (for special vertical alignment)
431 GetInfo().Y( nOldY );
432
433 bFirst &= !pPor->GetLen();
434 if( pNext || !pPor->IsMarginPortion() )
435 pPor->Move( GetInfo() );
436 if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
437 pArrow = static_cast<SwArrowPortion*>(pPor);
438
439 pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
440 // #i16816# tagged pdf support
441 ( GetInfo().GetVsh() &&
443 pNext && pNext->IsHolePortion() ) ?
444 pNext :
445 nullptr;
446 }
447
448 // delete underline font
449 delete GetInfo().GetUnderFnt();
450 GetInfo().SetUnderFnt( nullptr );
451
452 // paint remaining stuff
453 if( bDrawInWindow )
454 {
455 // If special vertical alignment is enabled, GetInfo().Y() is the
456 // top of the current line. Therefore is has to be adjusted for
457 // the painting of the remaining stuff. We first store the old value.
458 const SwTwips nOldY = GetInfo().Y();
459
460 if( !GetNextLine() &&
461 GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
462 GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() &&
463 GetInfo().GetIdx() >= TextFrameIndex(GetInfo().GetText().getLength()))
464 {
465 bool bHasRedlineEnd( GetRedln() && m_pCurr->HasRedlineEnd() );
466 RedlineType eRedlineEnd = bHasRedlineEnd ? m_pCurr->GetRedlineEndType() : RedlineType::None;
467 if( bHasRedlineEnd )
468 {
469 TextFrameIndex nOffset = GetInfo().GetIdx();
470 SeekStartAndChg( GetInfo(), true );
471 std::pair<SwTextNode const*, sal_Int32> const pos(
472 GetTextFrame()->MapViewToModel(nOffset));
473 GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
474 }
475 const SwTmpEndPortion aEnd( *pEndTempl,
476 bHasRedlineEnd && eRedlineEnd != RedlineType::Delete ? m_pFont->GetUnderline() : LINESTYLE_NONE,
477 bHasRedlineEnd && eRedlineEnd == RedlineType::Delete ? m_pFont->GetStrikeout() : STRIKEOUT_NONE,
478 bHasRedlineEnd ? m_pFont->GetColor() : COL_AUTO );
479 GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
480
481 if ( bAdjustBaseLine )
482 GetInfo().Y( GetInfo().GetPos().Y()
483 + AdjustBaseLine( *m_pCurr, &aEnd ) );
484 GetInfo().X( GetInfo().X() +
485 ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) );
486 aEnd.Paint( GetInfo() );
487 GetInfo().Y( nOldY );
488 }
489 if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
490 {
491 const bool bNextUndersized =
492 ( GetTextFrame()->GetNext() &&
495 static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ;
496
497 if( bUnderSized || bNextUndersized )
498 {
499 if ( bAdjustBaseLine )
500 GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() );
501
502 // Left arrow (text overflowing)
503 if( pArrow )
504 GetInfo().DrawRedArrow( *pArrow );
505
506 // GetInfo().Y() must be current baseline
507 SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom();
508 if( ( nDiff > 0 &&
509 (GetEnd() < TextFrameIndex(GetInfo().GetText().getLength()) ||
510 ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
511 (nDiff >= 0 && bNextUndersized) )
512
513 {
514 // Right arrow (text overflowing)
515 SwArrowPortion aArrow( GetInfo() );
516 GetInfo().DrawRedArrow( aArrow );
517 }
518
519 GetInfo().Y( nOldY );
520 }
521 }
522 }
523
524 if( m_pCurr->IsClipping() )
525 rClip.ChgClip( rPaint, m_pFrame );
526}
527
529 tools::Long nAdjustBaseLine )
530{
531 // Check if common underline should not be continued
532 if ( IsUnderlineBreak( *pPor, *m_pFont ) )
533 {
534 // delete underline font
535 delete GetInfo().GetUnderFnt();
536 GetInfo().SetUnderFnt( nullptr );
537 return;
538 }
539 // Reuse calculated underline font as much as possible.
540 if (GetInfo().GetUnderFnt() &&
541 GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + TextFrameIndex(1))
542 {
543 SwFont &rFont = GetInfo().GetUnderFnt()->GetFont();
544 const Color aColor = GetUnderColor( GetInfo().GetFont() );
545 if ( GetUnderColor( &rFont ) != aColor )
546 rFont.SetColor( aColor );
547 return;
548 }
549
550 // If current underline matches the common underline font, we continue
551 // to use the common underline font.
552 // Bug 120769:Color of underline display wrongly
553 if ( GetInfo().GetUnderFnt() &&
554 GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
556 return;
557 //Bug 120769(End)
558
559 OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(),
560 "CheckSpecialUnderline without underlined font" );
561 MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) );
562 const SwFont* pParaFnt = GetAttrHandler().GetFont();
563 if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
564 aUnderMulti.SelectAll();
565
566 if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
567 {
568 // first, add the paragraph properties to MultiSelection - if there are
569 // Hints too, they will override the positions if they're added later
570 sal_Int32 nTmp(0);
571 for (auto const& e : pMerged->extents)
572 {
573 if (const SvxUnderlineItem* pItem = e.pNode->GetSwAttrSet().GetItemIfSet(
575 {
576 const bool bUnderSelect(m_pFont->GetUnderline() ==
577 pItem->GetLineStyle());
578 aUnderMulti.Select(Range(nTmp, nTmp + e.nEnd - e.nStart - 1),
579 bUnderSelect);
580 }
581 nTmp += e.nEnd - e.nStart;
582 }
583 }
584
585 SwTextNode const* pNode(nullptr);
587 for (SwTextAttr const* pTextAttr = iter.NextAttr(&pNode); pTextAttr;
588 pTextAttr = iter.NextAttr(&pNode))
589 {
590 SvxUnderlineItem const*const pItem =
592
593 if (pItem)
594 {
595 TextFrameIndex const nStart(
596 GetTextFrame()->MapModelToView(pNode, pTextAttr->GetStart()));
597 TextFrameIndex const nEnd(
598 GetTextFrame()->MapModelToView(pNode, *pTextAttr->End()));
599 if (nEnd > nStart)
600 {
601 const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
602 aUnderMulti.Select(Range(sal_Int32(nStart), sal_Int32(nEnd) - 1),
603 bUnderSelect);
604 }
605 }
606 }
607
608 const TextFrameIndex nIndx = GetInfo().GetIdx();
609 TextFrameIndex nUnderEnd(0);
610 const size_t nCnt = aUnderMulti.GetRangeCount();
611
612 // find the underline range the current portion is contained in
613 for( size_t i = 0; i < nCnt; ++i )
614 {
615 const Range& rRange = aUnderMulti.GetRange( i );
616 if (nUnderEnd == TextFrameIndex(rRange.Min()))
617 nUnderEnd = TextFrameIndex(rRange.Max());
618 else if (nIndx >= TextFrameIndex(rRange.Min()))
619 {
620 nUnderEnd = TextFrameIndex(rRange.Max());
621 }
622 else
623 break;
624 }
625
626 if ( GetEnd() && GetEnd() <= nUnderEnd )
627 nUnderEnd = GetEnd() - TextFrameIndex(1);
628
629 // calculate the new common underline font
630 SwFont* pUnderlineFnt = nullptr;
631 Point aCommonBaseLine;
632
633 // check, if underlining is not isolated
634 if (nIndx + GetInfo().GetLen() < nUnderEnd + TextFrameIndex(1))
635 {
636 // here starts the algorithm for calculating the underline font
637 SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
638 SwAttrIter aIter(*GetInfo().GetTextFrame()->GetTextNodeFirst(),
639 rScriptInfo, GetTextFrame());
640
641 TextFrameIndex nTmpIdx = nIndx;
642 sal_uLong nSumWidth = 0;
643 sal_uLong nSumHeight = 0;
644 sal_uLong nBold = 0;
645 sal_uInt16 nMaxBaseLineOfst = 0;
646 int nNumberOfPortions = 0;
647
648 while (nTmpIdx <= nUnderEnd && pPor)
649 {
650 if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
651 pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
652 pPor->IsHolePortion() ||
653 ( pPor->IsMultiPortion() && ! static_cast<const SwMultiPortion*>(pPor)->IsBidi() ) )
654 break;
655
656 aIter.Seek( nTmpIdx );
657 if ( aIter.GetFnt()->GetEscapement() < 0 || m_pFont->IsWordLineMode() ||
658 SvxCaseMap::SmallCaps == m_pFont->GetCaseMap() )
659 break;
660
661 if ( !aIter.GetFnt()->GetEscapement() )
662 {
663 nSumWidth += pPor->Width();
664 const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
665
666 // If we do not have a common baseline we take the baseline
667 // and the font of the lowest portion.
668 if ( nAdjustBaseLine )
669 {
670 const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *m_pCurr, pPor );
671 if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
672 {
673 nMaxBaseLineOfst = nTmpBaseLineOfst;
674 nSumHeight = nFontHeight;
675 }
676 }
677 // in horizontal layout we build a weighted sum of the heights
678 else
679 nSumHeight += pPor->Width() * nFontHeight;
680
681 if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
682 nBold += pPor->Width();
683 }
684
685 ++nNumberOfPortions;
686
687 nTmpIdx += pPor->GetLen();
688 pPor = pPor->GetNextPortion();
689 }
690
691 // resulting height
692 if ( nNumberOfPortions > 1 && nSumWidth )
693 {
694 const sal_uLong nNewFontHeight = nAdjustBaseLine ?
695 nSumHeight :
696 nSumHeight / nSumWidth;
697
698 pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
699
700 // font height
701 const SwFontScript nActual = pUnderlineFnt->GetActual();
702 pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
703 nNewFontHeight ), nActual );
704
705 // font weight
706 if ( 2 * nBold > nSumWidth )
707 pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
708 else
709 pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
710
711 // common base line
712 aCommonBaseLine.setY( nAdjustBaseLine + nMaxBaseLineOfst );
713 }
714 }
715
716 // an escaped redlined portion should also have a special underlining
717 if( ! pUnderlineFnt && m_pFont->GetEscapement() > 0 && GetRedln() &&
718 GetRedln()->ChkSpecialUnderline() )
719 pUnderlineFnt = new SwFont( *m_pFont );
720
721 delete GetInfo().GetUnderFnt();
722
723 if ( pUnderlineFnt )
724 {
725 pUnderlineFnt->SetProportion( 100 );
726 pUnderlineFnt->SetEscapement( 0 );
727 pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
728 pUnderlineFnt->SetOverline( LINESTYLE_NONE );
729 const Color aFillColor( COL_TRANSPARENT );
730 pUnderlineFnt->SetFillColor( aFillColor );
731
732 GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt, nUnderEnd,
733 aCommonBaseLine ) );
734 }
735 else
736 // I'm sorry, we do not have a special underlining font for you.
737 GetInfo().SetUnderFnt( nullptr );
738}
739
740/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
const Range & GetRange(sal_Int32 nRange) const
sal_Int32 GetRangeCount() const
bool Select(sal_Int32 nIndex, bool bSelect=true)
void SelectAll(bool bSelect=true)
tools::Long Max() const
tools::Long Min() const
constexpr tools::Long Width() const
FontLineStyle GetLineStyle() const
Indicator that the content does not fit into a fixed height frame (red triangle on the UI).
Definition: porrst.hxx:116
const SwFont * GetFont() const
Definition: atrhndl.hxx:111
SwAttrHandler & GetAttrHandler()
Definition: itratr.hxx:109
SwRedlineItr * GetRedln()
Definition: itratr.hxx:81
SwFont * GetFnt()
Definition: itratr.hxx:103
bool Seek(TextFrameIndex nPos)
Enables the attributes used at char pos nPos in the logical font.
Definition: itratr.cxx:306
SwFont * m_pFont
Definition: itratr.hxx:39
void SetRedline(const RedlineType eRedline)
Definition: porrst.hxx:85
bool IsFollow() const
Definition: porfld.hxx:83
bool HasFollow() const
Definition: porfld.hxx:95
void SetOverline(const FontLineStyle eOverline)
Definition: swfont.hxx:564
void SetStrikeout(const FontStrikeout eStrikeout)
Definition: swfont.hxx:579
void SetEscapement(const short nNewEsc)
Definition: swfont.hxx:788
const Size & GetSize(SwFontScript nWhich) const
Definition: swfont.hxx:206
FontLineStyle GetUnderline() const
Definition: swfont.hxx:272
short GetEscapement() const
Definition: swfont.hxx:279
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:769
FontStrikeout GetStrikeout() const
Definition: swfont.hxx:276
void SetSize(const Size &rSize, const SwFontScript nWhich)
Definition: swfont.hxx:741
void SetFillColor(const Color &rColor)
Definition: swfont.hxx:440
const Color & GetUnderColor() const
Definition: swfont.hxx:273
SwFontScript GetActual() const
Definition: swfont.hxx:184
SvxCaseMap GetCaseMap() const
Definition: swfont.hxx:280
bool IsWordLineMode() const
Definition: swfont.hxx:278
FontWeight GetWeight() const
Definition: swfont.hxx:285
void SetColor(const Color &rColor)
Definition: swfont.hxx:418
const Color & GetColor() const
Definition: swfont.hxx:277
void ChgPhysFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.cxx:893
void SetWeight(const FontWeight eWeight, const SwFontScript nWhich)
Definition: swfont.hxx:536
tools::Long GetHeight() const
Definition: swfont.hxx:284
const SwRect & getFrameArea() const
Definition: frame.hxx:179
const SwRect & getFramePrintArea() const
Definition: frame.hxx:180
bool IsTextFrame() const
Definition: frame.hxx:1240
SwFrame * GetNext()
Definition: frame.hxx:682
bool IsInTab() const
Definition: frame.hxx:961
tools::Long GetBottomMargin() const
Definition: ssfrm.cxx:46
tools::Long GetTopMargin() const
Definition: ssfrm.cxx:44
bool HasSpecialAlign(bool bVert) const
Definition: inftxt.hxx:86
bool HasRedline() const
Definition: porlay.hxx:135
bool IsRest() const
Definition: porlay.hxx:129
SwLinePortion * GetFirstPortion() const
Definition: porlay.cxx:849
bool IsClipping() const
Definition: porlay.hxx:154
bool HasUnderscore() const
Definition: porlay.hxx:147
RedlineType GetRedlineEndType() const
Definition: porlay.hxx:139
bool HasRedlineEnd() const
Definition: porlay.hxx:137
std::vector< tools::Long > * GetpLLSpaceAdd() const
Definition: porlay.hxx:197
std::deque< sal_uInt16 > * GetpKanaComp() const
Definition: porlay.hxx:202
Base class for anything that can be part of a line in the Writer layout.
Definition: porlin.hxx:52
bool IsMarginPortion() const
Definition: porlin.hxx:133
bool IsArrowPortion() const
Definition: porlin.hxx:142
bool InTextGrp() const
Definition: porlin.hxx:105
SwLinePortion * GetNextPortion() const
Definition: porlin.hxx:75
bool InNumberGrp() const
Definition: porlin.hxx:109
bool IsPostItsPortion() const
Definition: porlin.hxx:137
virtual void Paint(const SwTextPaintInfo &rInf) const =0
TextFrameIndex GetLen() const
Definition: porlin.hxx:77
void Move(SwTextPaintInfo &rInf)
Definition: porlin.cxx:272
SwTwips GetHangingBaseline() const
Definition: porlin.hxx:89
SwTwips & GetAscent()
Definition: porlin.hxx:80
bool InSpaceGrp() const
Definition: porlin.hxx:116
bool InTabGrp() const
Definition: porlin.hxx:107
virtual tools::Long CalcSpacing(tools::Long nSpaceAdd, const SwTextSizeInfo &rInf) const
Definition: porlin.cxx:309
bool IsBreakPortion() const
Definition: porlin.hxx:121
bool IsQuoVadisPortion() const
Definition: porlin.hxx:123
bool IsMultiPortion() const
Definition: porlin.hxx:143
bool IsHolePortion() const
Definition: porlin.hxx:135
bool InFieldGrp() const
Definition: porlin.hxx:111
bool IsFlyPortion() const
Definition: porlin.hxx:134
bool IsFlyCntPortion() const
Definition: porlin.hxx:119
void PrePaint(const SwTextPaintInfo &rInf, const SwLinePortion *pLast) const
Definition: porlin.cxx:77
bool IsBidi() const
Definition: pormulti.hxx:132
SwScriptInfo & GetScriptInfo()
Definition: porlay.hxx:291
SwTwips Width() const
Definition: possiz.hxx:51
SwTwips Height() const
Definition: possiz.hxx:49
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
void Height(tools::Long nNew)
Definition: swrect.hxx:193
void Top(const tools::Long nTop)
Definition: swrect.hxx:206
void Right(const tools::Long nRight)
Definition: swrect.hxx:202
void Bottom(const tools::Long nBottom)
Definition: swrect.hxx:211
void Left(const tools::Long nLeft)
Definition: swrect.hxx:197
short Seek(SwFont &rFnt, SwNodeOffset nNode, sal_Int32 nNew, sal_Int32 nOld)
Definition: redlnitr.cxx:739
bool IsChg() const
Definition: txtpaint.hxx:54
void ChgClip(const SwRect &rRect, const SwTextFrame *pFrame=nullptr, bool bEnlargeRect=false, sal_Int32 nEnlargeTop=0, sal_Int32 nEnlargeBottom=0)
Definition: txtpaint.hxx:47
sal_uInt16 GetTabPos() const
Definition: portab.hxx:38
void GetAdjusted() const
Definition: itrtxt.hxx:250
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
SwTwips AdjustBaseLine(const SwLineLayout &rLine, const SwLinePortion *pPor, SwTwips nPorHeight=0, SwTwips nAscent=0, const bool bAutoToCentered=false) const
Definition: itrtxt.cxx:215
void AddExtraBlankWidth()
Definition: itrcrsr.cxx:403
void CtorInitTextCursor(SwTextFrame *pFrame, SwTextSizeInfo *pInf)
Definition: itrcrsr.cxx:394
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:166
SwParaPortion * GetParaPortion()
Definition: inftxt.hxx:121
TextFrameIndex GetEnd() const
Definition: itrtxt.hxx:89
SwTwips Y() const
Definition: itrtxt.hxx:90
bool SeekAndChgBefore(SwTextSizeInfo &rInf)
Definition: itrtxt.hxx:316
TextFrameIndex GetStart() const
Definition: itrtxt.hxx:88
bool SeekStartAndChg(SwTextSizeInfo &rInf, const bool bPara=false)
Definition: itrtxt.hxx:324
const SwLineLayout * GetPrevLine()
Definition: itrtxt.cxx:145
SwLineLayout * m_pCurr
Definition: itrtxt.hxx:36
SwTextFrame * m_pFrame
Definition: itrtxt.hxx:34
const SwLineLayout * GetCurr() const
Definition: itrtxt.hxx:83
sal_uInt16 GetLineNr() const
Definition: itrtxt.hxx:87
SwTextFrame * GetTextFrame()
Definition: itrtxt.hxx:134
void CalcAscentAndHeight(SwTwips &rAscent, SwTwips &rHeight) const
Definition: itrtxt.cxx:64
const SwLineInfo & GetLineInfo() const
Definition: itrtxt.hxx:128
const SwLineLayout * GetNextLine() const
Definition: itrtxt.cxx:135
SwTextInfo * m_pInf
Definition: itrtxt.hxx:35
bool SeekAndChg(SwTextSizeInfo &rInf)
Definition: itrtxt.hxx:311
sal_uInt16 GetDropLines() const
Definition: itrtxt.hxx:202
Point GetTopLeft() const
Definition: itrtxt.hxx:186
SwTwips Right() const
Definition: itrtxt.hxx:181
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
void SetpSpaceAdd(std::vector< tools::Long > *pNew)
Definition: inftxt.hxx:448
void SetPaintOfst(const SwTwips nNew)
Definition: inftxt.hxx:746
SwTwips X() const
Definition: inftxt.hxx:382
void SetPos(const Point &rNew)
Definition: inftxt.hxx:433
const Point & GetPos() const
Definition: inftxt.hxx:432
void DrawRedArrow(const SwLinePortion &rPor) const
Definition: inftxt.cxx:1012
void ResetSpaceIdx()
Definition: inftxt.hxx:440
SwTwips Y() const
Definition: inftxt.hxx:384
SwLinePortion * CalcPaintOfst(const SwRect &rPaint)
Definition: itrpaint.cxx:73
void DrawTextLine(const SwRect &rPaint, SwSaveClip &rClip, const bool bUnderSz, ::std::optional< SwTaggedPDFHelper > &roTaggedLabel, ::std::optional< SwTaggedPDFHelper > &roTaggedParagraph, bool isPDFTaggingEnabled)
Definition: itrpaint.cxx:121
void PaintMultiPortion(const SwRect &rPaint, SwMultiPortion &rMulti, const SwMultiPortion *pEnvPor=nullptr)
Definition: pormulti.cxx:1520
SwTextPaintInfo & GetInfo()
Definition: itrpaint.hxx:63
void CheckSpecialUnderline(const SwLinePortion *pPor, tools::Long nAdjustBaseLine=0)
Definition: itrpaint.cxx:528
void CtorInitTextPainter(SwTextFrame *pFrame, SwTextPaintInfo *pInf)
Definition: itrpaint.cxx:64
bool m_bPaintDrop
Definition: itrpaint.hxx:32
SwTextFrame * GetTextFrame()
Definition: inftxt.hxx:288
vcl::RenderContext * GetOut()
Definition: inftxt.hxx:225
SwViewShell * GetVsh()
Definition: inftxt.hxx:222
const SwViewOption & GetOpt() const
Definition: inftxt.hxx:239
void SetUnderFnt(SwUnderlineFont *pNew)
Definition: inftxt.hxx:236
void SetLen(const TextFrameIndex nNew)
Definition: inftxt.hxx:276
void ResetKanaIdx()
Definition: inftxt.hxx:323
bool OnWin() const
Definition: inftxt.hxx:193
void SetIdx(const TextFrameIndex nNew)
Definition: inftxt.hxx:274
void SetFont(SwFont *pNew)
Definition: inftxt.hxx:234
SwUnderlineFont * GetUnderFnt() const
Definition: inftxt.hxx:237
void SetKanaComp(std::deque< sal_uInt16 > *pNew)
Definition: inftxt.hxx:326
const OUString & GetText() const
Definition: inftxt.hxx:240
TextFrameIndex GetIdx() const
Definition: inftxt.hxx:273
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: porrst.cxx:66
void SetPos(const Point &rPoint)
Definition: swfont.hxx:977
const Point & GetPos() const
Definition: swfont.hxx:974
SwFont & GetFont()
Definition: swfont.hxx:969
bool IsParagraph(bool bHard=false) const
Definition: viewopt.hxx:371
bool IsPDFExport() const
Definition: viewopt.hxx:590
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:434
SwTextAttr const * NextAttr(SwTextNode const **ppNode=nullptr)
Definition: txtfrm.cxx:91
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
RedlineType
LINESTYLE_NONE
STRIKEOUT_NONE
WEIGHT_BOLD
WEIGHT_NORMAL
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
static Color GetUnderColor(const SwFont *pFont)
Definition: itrpaint.cxx:58
bool IsUnderlineBreak(const SwLinePortion &rPor, const SwFont &rFnt)
Definition: itrpaint.cxx:47
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
Extracts pool item of type nWhich from rAttr.
Definition: atrstck.cxx:157
double getLength(const B2DPolygon &rCandidate)
int i
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1183
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(MergedPara const &, TextFrameIndex nIndex)
Definition: txtfrm.cxx:1164
long Long
vcl::Font GetFont(vcl::Font const &rFont, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2650
sal_uIntPtr sal_uLong
Describes parts of multiple text nodes, which will form a text frame, even when redlines are hidden a...
Definition: txtfrm.hxx:971
tools::Long GetLen(const Point &rPnt)
SwFontScript
Definition: swfont.hxx:124
tools::Long SwTwips
Definition: swtypes.hxx:51
oslFileHandle & pOut
size_t pos