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
73SwLinePortion *SwTextPainter::CalcPaintOfst(const SwRect &rPaint, bool& rbSkippedNumPortions)
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 if (pPor->InNumberGrp()
102 && !static_cast<SwNumberPortion const*>(pPor)->HasFollow())
103 {
104 rbSkippedNumPortions = true; // all numbering portions were skipped?
105 }
106 pLast = pPor;
107 pPor = pPor->GetNextPortion();
108 }
109
110 // 7529: if PostIts return also pLast.
111 if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
112 {
113 pPor = pLast;
114 GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
115 }
116 }
117 return pPor;
118}
119
120// There are two possibilities to output transparent font:
121// 1) DrawRect on the whole line and DrawText afterwards
122// (objectively fast, subjectively slow)
123// 2) For every portion a DrawRect with subsequent DrawText is done
124// (objectively slow, subjectively fast)
125// Since the user usually judges subjectively the second method is set as default.
127 const bool bUnderSized,
128 ::std::optional<SwTaggedPDFHelper> & roTaggedLabel,
129 ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph,
130 bool const isPDFTaggingEnabled)
131{
132#if OSL_DEBUG_LEVEL > 1
133// sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
134// sal_uInt16 nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
135#endif
136
137 // maybe catch-up adjustment
138 GetAdjusted();
144 // The size of the frame
145 GetInfo().SetIdx( GetStart() );
147
148 const bool bDrawInWindow = GetInfo().OnWin();
149
150 // 6882: blank lines can't be optimized by removing them if Formatting Marks are shown
151 const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetText().isEmpty();
152
153 bool bSkippedNumPortions(false);
154 SwLinePortion *pPor = bEndPor ? m_pCurr->GetFirstPortion() : CalcPaintOfst(rPaint, bSkippedNumPortions);
155
156 if (bSkippedNumPortions) // ugly but hard to check earlier in PaintSwFrame:
157 { // there is a num portion but it is outside of the frame area and not painted
158 assert(!roTaggedLabel);
159 assert(!roTaggedParagraph);
160 Frame_Info aFrameInfo(*m_pFrame, false); // open LBody
161 roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *GetInfo().GetOut());
162 }
163
164 // Optimization!
165 SwTwips nMaxRight = std::min<SwTwips>( rPaint.Right(), Right() );
166 const SwTwips nTmpLeft = GetInfo().X();
167 //compatibility settings: allow tabstop text to exceed right margin
168 const auto& iDSA = GetInfo().GetTextFrame()->GetDoc().getIDocumentSettingAccess();
169 const bool bTabOverMargin = iDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
170 const bool bTabOverSpacing = iDSA.get(DocumentSettingId::TAB_OVER_SPACING);
171 if (bTabOverMargin || bTabOverSpacing)
172 {
173 SwLinePortion* pPorIter = pPor;
174 while( pPorIter )
175 {
176 if( pPorIter->InTabGrp() )
177 {
178 const SwTabPortion* pTabPor = static_cast<SwTabPortion*>(pPorIter);
179 const SwTwips nTabPos = nTmpLeft + pTabPor->GetTabPos();
180 if( nMaxRight < nTabPos )
181 {
182 nMaxRight = rPaint.Right();
183 break;
184 }
185 }
186 pPorIter = pPorIter->GetNextPortion();
187 }
188 }
189 if( !bEndPor && nTmpLeft >= nMaxRight )
190 return;
191
192 // DropCaps!
193 // 7538: of course for the printer, too
194 if( !m_bPaintDrop )
195 {
196 // 8084: Optimization, less painting
197 // AMA: By 8084 7538 has been revived
198 // bDrawInWindow removed, so that DropCaps also can be printed
200 && GetDropLines() >= GetLineNr();
201 }
202
203 SwTwips nTmpHeight, nTmpAscent;
204 CalcAscentAndHeight( nTmpAscent, nTmpHeight );
205
206 // bClip decides if there's a need to clip
207 // The whole thing must be done before retouching
208
209 bool bClip = ( bDrawInWindow || bUnderSized ) && !rClip.IsChg();
210 if( bClip && pPor )
211 {
212 // If TopLeft or BottomLeft of the line are outside, the we must clip.
213 // The check for Right() is done in the output loop ...
214
215 if( GetInfo().GetPos().X() < rPaint.Left() ||
216 GetInfo().GetPos().Y() < rPaint.Top() ||
217 GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
218 {
219 bClip = false;
220 rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
221 }
222#if OSL_DEBUG_LEVEL > 1
223 static bool bClipAlways = false;
224 if( bClip && bClipAlways )
225 { bClip = false;
226 rClip.ChgClip( rPaint );
227 }
228#endif
229 }
230
231 // Alignment
233 Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
234 if ( aPnt1.X() < rPaint.Left() )
235 aPnt1.setX( rPaint.Left() );
236 if ( aPnt1.Y() < rPaint.Top() )
237 aPnt1.setY( rPaint.Top() );
238 Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
239 GetInfo().GetPos().Y() + nTmpHeight );
240 if ( aPnt2.X() > rPaint.Right() )
241 aPnt2.setX( rPaint.Right() );
242 if ( aPnt2.Y() > rPaint.Bottom() )
243 aPnt2.setY( rPaint.Bottom() );
244
245 const SwRect aLineRect( aPnt1, aPnt2 );
246
247 if( m_pCurr->IsClipping() )
248 {
249 const SwTextFrame& rFrame = *GetInfo().GetTextFrame();
250 // tdf#117448 at small fixed line height, enlarge clipping area in table cells
251 // to show previously clipped text content on the area of paragraph margins
252 if ( rFrame.IsInTab() )
253 rClip.ChgClip( aLineRect, m_pFrame, false, rFrame.GetTopMargin(), rFrame.GetBottomMargin() );
254 else
255 rClip.ChgClip( aLineRect, m_pFrame );
256 bClip = false;
257 }
258
259 if( !pPor && !bEndPor )
260 return;
261
262 // Baseline output also if non-TextPortion (compare TabPor with Fill)
263 // if no special vertical alignment is used,
264 // we calculate Y value for the whole line
265 SwTextGridItem const*const pGrid(GetGridItem(GetTextFrame()->FindPageFrame()));
266 const bool bAdjustBaseLine =
267 GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) ||
268 ( nullptr != pGrid ) || m_pCurr->GetHangingBaseline();
269 const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
270 if ( ! bAdjustBaseLine )
271 GetInfo().Y( nLineBaseLine );
272
273 // 7529: Pre-paint post-its
274 if( GetInfo().OnWin() && pPor && !pPor->Width() )
275 {
276 SeekAndChg( GetInfo() );
277
278 if( bAdjustBaseLine )
279 {
280 const SwTwips nOldY = GetInfo().Y();
281
282 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, nullptr,
283 GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
284 GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
285 ) );
286
287 pPor->PrePaint( GetInfo(), pPor );
288 GetInfo().Y( nOldY );
289 }
290 else
291 pPor->PrePaint( GetInfo(), pPor );
292 }
293
294 // 7923: EndPortions output chars, too, that's why we change the font
295 if( bEndPor )
297
298 const bool bRest = m_pCurr->IsRest();
299 bool bFirst = true;
300
301 SwArrowPortion *pArrow = nullptr;
302 // Reference portion for the paragraph end portion
303 SwLinePortion* pEndTempl = m_pCurr->GetFirstPortion();
304
305 while( pPor )
306 {
307 bool bSeeked = true;
308 GetInfo().SetLen( pPor->GetLen() );
309
310 const SwTwips nOldY = GetInfo().Y();
311
312 if ( bAdjustBaseLine )
313 {
314 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, pPor ) );
315
316 // we store the last portion, because a possible paragraph
317 // end character has the same font as this portion
318 // (only in special vertical alignment case, otherwise the first
319 // portion of the line is used)
320 if ( pPor->Width() && pPor->InTextGrp() )
321 pEndTempl = pPor;
322 }
323
324 // set redlining for line break symbol
325 if ( pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() && GetRedln() )
326 {
327 SeekAndChg( GetInfo() );
328 if ( m_pCurr->GetRedlineEndType() != RedlineType::None )
329 static_cast<SwBreakPortion&>(*pPor).SetRedline( m_pCurr->GetRedlineEndType() );
330 }
331
332 // A special case are GluePortions which output blanks.
333
334 // 6168: Avoid that the rest of a FieldPortion gets the attributes of the
335 // next portion with SeekAndChgBefore():
336 if( bRest && pPor->InFieldGrp() && !pPor->GetLen() )
338 else if ( pPor->IsQuoVadisPortion() )
339 {
340 // A remark on QuoVadis/ErgoSum:
341 // We use the Font set for the Paragraph for these portions.
342 // Thus, we initialize:
343 TextFrameIndex nOffset = GetInfo().GetIdx();
344 SeekStartAndChg( GetInfo(), true );
345 if( GetRedln() && m_pCurr->HasRedline() )
346 {
347 std::pair<SwTextNode const*, sal_Int32> const pos(
348 GetTextFrame()->MapViewToModel(nOffset));
349 GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
350 }
351 }
352 else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
353 SeekAndChg( GetInfo() );
354 else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
355 {
356 // Paragraph symbols should have the same font as the paragraph in front of them,
357 // except for the case that there's redlining in the paragraph
358 if( GetRedln() )
359 SeekAndChg( GetInfo() );
360 else
362 }
363 else
364 bSeeked = false;
365
366 // bRest = false;
367
368 // If the end of the portion juts out, it is clipped.
369 // A safety distance of half the height is added, so that
370 // TTF-"f" isn't overlapping into the page margin.
371 if( bClip &&
372 GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
373 {
374 bClip = false;
375 rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
376 }
377
378 // Portions, which lay "below" the text like post-its
379 SwLinePortion *pNext = pPor->GetNextPortion();
380 if( GetInfo().OnWin() && pNext && !pNext->Width() )
381 {
382 // Fix 11289: Fields were omitted here because of Last!=Owner during
383 // loading Brief.sdw. Now the fields are allowed again,
384 // by bSeeked Last!=Owner is being avoided.
385 if ( !bSeeked )
386 SeekAndChg( GetInfo() );
387 pNext->PrePaint( GetInfo(), pPor );
388 }
389
390 // We calculate a separate font for underlining.
391 CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
392 SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
393 if ( pUnderLineFnt )
394 {
395 const Point aTmpPoint( GetInfo().X(),
396 bAdjustBaseLine ?
397 pUnderLineFnt->GetPos().Y() :
398 nLineBaseLine );
399 pUnderLineFnt->SetPos( aTmpPoint );
400 }
401
402 // in extended input mode we do not want a common underline font.
403 SwUnderlineFont* pOldUnderLineFnt = nullptr;
404 if ( GetRedln() && GetRedln()->ExtOn() )
405 {
406 pOldUnderLineFnt = GetInfo().GetUnderFnt();
407 GetInfo().SetUnderFnt( nullptr );
408 }
409
410 // multiple numbering portions are possible :(
411 if ((pPor->InNumberGrp() // also footnote label
412 // weird special case, bullet with soft hyphen
413 || (pPor->InHyphGrp() && pNext && pNext->InNumberGrp()))
414 && !roTaggedLabel) // note: CalcPaintOfst may skip some portions
415 {
416 assert(isPDFTaggingEnabled);
417 Por_Info aPorInfo(*pPor, *this, true); // open Lbl
418 roTaggedLabel.emplace(nullptr, nullptr, &aPorInfo, *pOut);
419 }
420
421 {
422 // #i16816# tagged pdf support
423 Por_Info aPorInfo(*pPor, *this, false);
424 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut );
425
426 if( pPor->IsMultiPortion() )
427 PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) );
428 else
429 pPor->Paint( GetInfo() );
430 }
431
432 // lazy open LBody and paragraph tag after num portions have been painted to Lbl
433 if (pPor->InNumberGrp() // also footnote label
434 // note: numbering portion may be split if it has multiple scripts
435 && !static_cast<SwNumberPortion const*>(pPor)->HasFollow()) // so wait for the last one
436 {
437 assert(roTaggedLabel);
438 roTaggedLabel.reset(); // close Lbl
439 assert(!roTaggedParagraph);
440 Frame_Info aFrameInfo(*m_pFrame, false); // open LBody
441 roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *pOut);
442 }
443
444 // reset underline font
445 if ( pOldUnderLineFnt )
446 GetInfo().SetUnderFnt( pOldUnderLineFnt );
447
448 // reset (for special vertical alignment)
449 GetInfo().Y( nOldY );
450
451 bFirst &= !pPor->GetLen();
452 if( pNext || !pPor->IsMarginPortion() )
453 pPor->Move( GetInfo() );
454 if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
455 pArrow = static_cast<SwArrowPortion*>(pPor);
456
457 pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
458 // #i16816# tagged pdf support
459 ( GetInfo().GetVsh() &&
461 pNext && pNext->IsHolePortion() ) ?
462 pNext :
463 nullptr;
464 if (!pPor && isPDFTaggingEnabled && !roTaggedParagraph)
465 { // check if the end of the list label is off-screen
466 auto FindEndOfNumbering = [&](SwLinePortion const* pP) {
467 while (pP)
468 {
469 if (pP->InNumberGrp()
470 && !static_cast<SwNumberPortion const*>(pP)->HasFollow())
471 {
472 if (roTaggedLabel)
473 {
474 roTaggedLabel.reset();
475 } // else, if the numbering isn't visible at all, no Lbl
476 Frame_Info aFrameInfo(*m_pFrame, false); // open LBody
477 roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *GetInfo().GetOut());
478 return true;
479 }
480 pP = pP->GetNextPortion();
481 }
482 return false;
483 };
484 if (!FindEndOfNumbering(pNext)) // check rest of current line
485 {
486 // check lines that will be cut off
487 if (rPaint.Bottom() < Y() + GetLineHeight())
488 {
489 for (SwLineLayout const* pLine = GetNext(); pLine; pLine = pLine->GetNext())
490 {
491 if (FindEndOfNumbering(pLine->GetFirstPortion()))
492 {
493 break;
494 }
495 }
496 }
497 }
498 }
499 }
500
501 // delete underline font
502 delete GetInfo().GetUnderFnt();
503 GetInfo().SetUnderFnt( nullptr );
504
505 // paint remaining stuff
506 if( bDrawInWindow )
507 {
508 // If special vertical alignment is enabled, GetInfo().Y() is the
509 // top of the current line. Therefore is has to be adjusted for
510 // the painting of the remaining stuff. We first store the old value.
511 const SwTwips nOldY = GetInfo().Y();
512
513 if( !GetNextLine() &&
514 GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
515 GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() &&
516 GetInfo().GetIdx() >= TextFrameIndex(GetInfo().GetText().getLength()))
517 {
518 bool bHasRedlineEnd( GetRedln() && m_pCurr->HasRedlineEnd() );
519 RedlineType eRedlineEnd = bHasRedlineEnd ? m_pCurr->GetRedlineEndType() : RedlineType::None;
520 if( bHasRedlineEnd )
521 {
522 TextFrameIndex nOffset = GetInfo().GetIdx();
523 SeekStartAndChg( GetInfo(), true );
524 std::pair<SwTextNode const*, sal_Int32> const pos(
525 GetTextFrame()->MapViewToModel(nOffset));
526 GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
527 }
528 const SwTmpEndPortion aEnd( *pEndTempl,
529 bHasRedlineEnd && eRedlineEnd != RedlineType::Delete ? m_pFont->GetUnderline() : LINESTYLE_NONE,
530 bHasRedlineEnd && eRedlineEnd == RedlineType::Delete ? m_pFont->GetStrikeout() : STRIKEOUT_NONE,
531 bHasRedlineEnd ? m_pFont->GetColor() : COL_AUTO );
532 GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
533
534 if ( bAdjustBaseLine )
535 GetInfo().Y( GetInfo().GetPos().Y()
536 + AdjustBaseLine( *m_pCurr, &aEnd ) );
537 GetInfo().X( GetInfo().X() +
538 ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) );
539 aEnd.Paint( GetInfo() );
540 GetInfo().Y( nOldY );
541 }
542 if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
543 {
544 const bool bNextUndersized =
545 ( GetTextFrame()->GetNext() &&
548 static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ;
549
550 if( bUnderSized || bNextUndersized )
551 {
552 if ( bAdjustBaseLine )
553 GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() );
554
555 // Left arrow (text overflowing)
556 if( pArrow )
557 GetInfo().DrawRedArrow( *pArrow );
558
559 // GetInfo().Y() must be current baseline
560 SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom();
561 if( ( nDiff > 0 &&
562 (GetEnd() < TextFrameIndex(GetInfo().GetText().getLength()) ||
563 ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
564 (nDiff >= 0 && bNextUndersized) )
565
566 {
567 // Right arrow (text overflowing)
568 SwArrowPortion aArrow( GetInfo() );
569 GetInfo().DrawRedArrow( aArrow );
570 }
571
572 GetInfo().Y( nOldY );
573 }
574 }
575 }
576
577 if( m_pCurr->IsClipping() )
578 rClip.ChgClip( rPaint, m_pFrame );
579}
580
582 tools::Long nAdjustBaseLine )
583{
584 // Check if common underline should not be continued
585 if ( IsUnderlineBreak( *pPor, *m_pFont ) )
586 {
587 // delete underline font
588 delete GetInfo().GetUnderFnt();
589 GetInfo().SetUnderFnt( nullptr );
590 return;
591 }
592 // Reuse calculated underline font as much as possible.
593 if (GetInfo().GetUnderFnt() &&
594 GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + TextFrameIndex(1))
595 {
596 SwFont &rFont = GetInfo().GetUnderFnt()->GetFont();
597 const Color aColor = GetUnderColor( GetInfo().GetFont() );
598 if ( GetUnderColor( &rFont ) != aColor )
599 rFont.SetColor( aColor );
600 return;
601 }
602
603 // If current underline matches the common underline font, we continue
604 // to use the common underline font.
605 // Bug 120769:Color of underline display wrongly
606 if ( GetInfo().GetUnderFnt() &&
607 GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
609 return;
610 //Bug 120769(End)
611
612 OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(),
613 "CheckSpecialUnderline without underlined font" );
614 MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) );
615 const SwFont* pParaFnt = GetAttrHandler().GetFont();
616 if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
617 aUnderMulti.SelectAll();
618
619 if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
620 {
621 // first, add the paragraph properties to MultiSelection - if there are
622 // Hints too, they will override the positions if they're added later
623 sal_Int32 nTmp(0);
624 for (auto const& e : pMerged->extents)
625 {
626 if (const SvxUnderlineItem* pItem = e.pNode->GetSwAttrSet().GetItemIfSet(
628 {
629 const bool bUnderSelect(m_pFont->GetUnderline() ==
630 pItem->GetLineStyle());
631 aUnderMulti.Select(Range(nTmp, nTmp + e.nEnd - e.nStart - 1),
632 bUnderSelect);
633 }
634 nTmp += e.nEnd - e.nStart;
635 }
636 }
637
638 SwTextNode const* pNode(nullptr);
640 for (SwTextAttr const* pTextAttr = iter.NextAttr(&pNode); pTextAttr;
641 pTextAttr = iter.NextAttr(&pNode))
642 {
643 SvxUnderlineItem const*const pItem =
645
646 if (pItem)
647 {
648 TextFrameIndex const nStart(
649 GetTextFrame()->MapModelToView(pNode, pTextAttr->GetStart()));
650 TextFrameIndex const nEnd(
651 GetTextFrame()->MapModelToView(pNode, *pTextAttr->End()));
652 if (nEnd > nStart)
653 {
654 const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
655 aUnderMulti.Select(Range(sal_Int32(nStart), sal_Int32(nEnd) - 1),
656 bUnderSelect);
657 }
658 }
659 }
660
661 const TextFrameIndex nIndx = GetInfo().GetIdx();
662 TextFrameIndex nUnderEnd(0);
663 const size_t nCnt = aUnderMulti.GetRangeCount();
664
665 // find the underline range the current portion is contained in
666 for( size_t i = 0; i < nCnt; ++i )
667 {
668 const Range& rRange = aUnderMulti.GetRange( i );
669 if (nUnderEnd == TextFrameIndex(rRange.Min()))
670 nUnderEnd = TextFrameIndex(rRange.Max());
671 else if (nIndx >= TextFrameIndex(rRange.Min()))
672 {
673 nUnderEnd = TextFrameIndex(rRange.Max());
674 }
675 else
676 break;
677 }
678
679 if ( GetEnd() && GetEnd() <= nUnderEnd )
680 nUnderEnd = GetEnd() - TextFrameIndex(1);
681
682 // calculate the new common underline font
683 SwFont* pUnderlineFnt = nullptr;
684 Point aCommonBaseLine;
685
686 // check, if underlining is not isolated
687 if (nIndx + GetInfo().GetLen() < nUnderEnd + TextFrameIndex(1))
688 {
689 // here starts the algorithm for calculating the underline font
690 SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
691 SwAttrIter aIter(*GetInfo().GetTextFrame()->GetTextNodeFirst(),
692 rScriptInfo, GetTextFrame());
693
694 TextFrameIndex nTmpIdx = nIndx;
695 sal_uLong nSumWidth = 0;
696 sal_uLong nSumHeight = 0;
697 sal_uLong nBold = 0;
698 sal_uInt16 nMaxBaseLineOfst = 0;
699 int nNumberOfPortions = 0;
700
701 while (nTmpIdx <= nUnderEnd && pPor)
702 {
703 if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
704 pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
705 pPor->IsHolePortion() ||
706 ( pPor->IsMultiPortion() && ! static_cast<const SwMultiPortion*>(pPor)->IsBidi() ) )
707 break;
708
709 aIter.Seek( nTmpIdx );
710 if ( aIter.GetFnt()->GetEscapement() < 0 || m_pFont->IsWordLineMode() ||
711 SvxCaseMap::SmallCaps == m_pFont->GetCaseMap() )
712 break;
713
714 if ( !aIter.GetFnt()->GetEscapement() )
715 {
716 nSumWidth += pPor->Width();
717 const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
718
719 // If we do not have a common baseline we take the baseline
720 // and the font of the lowest portion.
721 if ( nAdjustBaseLine )
722 {
723 const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *m_pCurr, pPor );
724 if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
725 {
726 nMaxBaseLineOfst = nTmpBaseLineOfst;
727 nSumHeight = nFontHeight;
728 }
729 }
730 // in horizontal layout we build a weighted sum of the heights
731 else
732 nSumHeight += pPor->Width() * nFontHeight;
733
734 if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
735 nBold += pPor->Width();
736 }
737
738 ++nNumberOfPortions;
739
740 nTmpIdx += pPor->GetLen();
741 pPor = pPor->GetNextPortion();
742 }
743
744 // resulting height
745 if ( nNumberOfPortions > 1 && nSumWidth )
746 {
747 const sal_uLong nNewFontHeight = nAdjustBaseLine ?
748 nSumHeight :
749 nSumHeight / nSumWidth;
750
751 pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
752
753 // font height
754 const SwFontScript nActual = pUnderlineFnt->GetActual();
755 pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
756 nNewFontHeight ), nActual );
757
758 // font weight
759 if ( 2 * nBold > nSumWidth )
760 pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
761 else
762 pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
763
764 // common base line
765 aCommonBaseLine.setY( nAdjustBaseLine + nMaxBaseLineOfst );
766 }
767 }
768
769 // an escaped redlined portion should also have a special underlining
770 if( ! pUnderlineFnt && m_pFont->GetEscapement() > 0 && GetRedln() &&
771 GetRedln()->ChkSpecialUnderline() )
772 pUnderlineFnt = new SwFont( *m_pFont );
773
774 delete GetInfo().GetUnderFnt();
775
776 if ( pUnderlineFnt )
777 {
778 pUnderlineFnt->SetProportion( 100 );
779 pUnderlineFnt->SetEscapement( 0 );
780 pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
781 pUnderlineFnt->SetOverline( LINESTYLE_NONE );
782 const Color aFillColor( COL_TRANSPARENT );
783 pUnderlineFnt->SetFillColor( aFillColor );
784
785 GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt, nUnderEnd,
786 aCommonBaseLine ) );
787 }
788 else
789 // I'm sorry, we do not have a special underlining font for you.
790 GetInfo().SetUnderFnt( nullptr );
791}
792
793/* 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...
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
const Range & GetRange(sal_Int32 nRange) const
sal_Int32 GetRangeCount() const
bool Select(sal_Int32 nIndex, bool bSelect=true)
void SelectAll(bool bSelect=true)
constexpr tools::Long Y() const
void setX(tools::Long nX)
void setY(tools::Long nY)
constexpr tools::Long X() const
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
IDocumentSettingAccess const & getIDocumentSettingAccess() const
Definition: doc.cxx:190
bool HasFollow() const
Definition: porfld.hxx:95
To take Asian or other languages into consideration, an SwFont object consists of 3 SwSubFonts (Latin...
Definition: swfont.hxx:135
void SetOverline(const FontLineStyle eOverline)
Definition: swfont.hxx:567
void SetStrikeout(const FontStrikeout eStrikeout)
Definition: swfont.hxx:582
void SetEscapement(const short nNewEsc)
Definition: swfont.hxx:791
const Size & GetSize(SwFontScript nWhich) const
Definition: swfont.hxx:209
FontLineStyle GetUnderline() const
Definition: swfont.hxx:275
short GetEscapement() const
Definition: swfont.hxx:282
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:772
FontStrikeout GetStrikeout() const
Definition: swfont.hxx:279
void SetSize(const Size &rSize, const SwFontScript nWhich)
Definition: swfont.hxx:744
void SetFillColor(const Color &rColor)
Definition: swfont.hxx:443
const Color & GetUnderColor() const
Definition: swfont.hxx:276
SwFontScript GetActual() const
Definition: swfont.hxx:187
SvxCaseMap GetCaseMap() const
Definition: swfont.hxx:283
bool IsWordLineMode() const
Definition: swfont.hxx:281
FontWeight GetWeight() const
Definition: swfont.hxx:288
void SetColor(const Color &rColor)
Definition: swfont.hxx:421
const Color & GetColor() const
Definition: swfont.hxx:280
void ChgPhysFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.cxx:893
void SetWeight(const FontWeight eWeight, const SwFontScript nWhich)
Definition: swfont.hxx:539
tools::Long GetHeight() const
Definition: swfont.hxx:287
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
Collection of SwLinePortion instances, representing one line of text.
Definition: porlay.hxx:79
bool HasRedline() const
Definition: porlay.hxx:135
bool IsRest() const
Definition: porlay.hxx:129
SwLineLayout * GetNext()
Definition: porlay.hxx:159
SwLinePortion * GetFirstPortion() const
Definition: porlay.cxx:841
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
bool InHyphGrp() const
Definition: porlin.hxx:108
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:404
void CtorInitTextCursor(SwTextFrame *pFrame, SwTextSizeInfo *pInf)
Definition: itrcrsr.cxx:395
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:168
SwDoc & GetDoc()
Definition: txtfrm.hxx:475
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
const SwLineLayout * GetNext() const
Definition: itrtxt.hxx:84
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
SwTwips GetLineHeight() const
Definition: itrtxt.hxx:116
SwTextFrame * m_pFrame
Definition: itrtxt.hxx:34
const SwLineLayout * GetCurr() const
Definition: itrtxt.hxx:83
sal_Int32 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:450
void SetPaintOfst(const SwTwips nNew)
Definition: inftxt.hxx:748
SwTwips X() const
Definition: inftxt.hxx:382
void SetPos(const Point &rNew)
Definition: inftxt.hxx:435
const Point & GetPos() const
Definition: inftxt.hxx:434
void DrawRedArrow(const SwLinePortion &rPor) const
Definition: inftxt.cxx:1024
void ResetSpaceIdx()
Definition: inftxt.hxx:442
SwTwips Y() const
Definition: inftxt.hxx:384
void DrawTextLine(const SwRect &rPaint, SwSaveClip &rClip, const bool bUnderSz, ::std::optional< SwTaggedPDFHelper > &roTaggedLabel, ::std::optional< SwTaggedPDFHelper > &roTaggedParagraph, bool isPDFTaggingEnabled)
Definition: itrpaint.cxx:126
SwLinePortion * CalcPaintOfst(const SwRect &rPaint, bool &rbSkippedNumPortions)
Definition: itrpaint.cxx:73
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:581
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:980
const Point & GetPos() const
Definition: swfont.hxx:977
SwFont & GetFont()
Definition: swfont.hxx:972
bool IsParagraph(bool bHard=false) const
Definition: viewopt.hxx:369
bool IsPDFExport() const
Definition: viewopt.hxx:588
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:452
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
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1270
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(MergedPara const &, TextFrameIndex nIndex)
Definition: txtfrm.cxx:1251
long Long
vcl::Font GetFont(vcl::Font const &rFont, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2676
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:991
tools::Long GetLen(const Point &rPnt)
SwFontScript
Definition: swfont.hxx:124
tools::Long SwTwips
Definition: swtypes.hxx:51
oslFileHandle & pOut
size_t pos