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