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
46 bool 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 
57 static 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  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.
120 void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
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();
133  GetInfo().ResetKanaIdx();
134  // The size of the frame
135  GetInfo().SetIdx( GetStart() );
136  GetInfo().SetPos( GetTopLeft() );
137 
138  const bool bDrawInWindow = GetInfo().OnWin();
139 
140  // 6882: blank lines can't be optimized by removing them if Formatting Marks are shown
141  const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetText().isEmpty();
142 
143  SwLinePortion *pPor = bEndPor ? m_pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
144 
145  // Optimization!
146  SwTwips nMaxRight = std::min<SwTwips>( rPaint.Right(), Right() );
147  const SwTwips nTmpLeft = GetInfo().X();
148  //compatibility setting: allow tabstop text to exceed right margin
149  if (GetInfo().GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_OVER_MARGIN))
150  {
151  SwLinePortion* pPorIter = pPor;
152  while( pPorIter )
153  {
154  if( pPorIter->InTabGrp() )
155  {
156  const SwTabPortion* pTabPor = static_cast<SwTabPortion*>(pPorIter);
157  const SwTwips nTabPos = nTmpLeft + pTabPor->GetTabPos();
158  if( nMaxRight < nTabPos )
159  {
160  nMaxRight = rPaint.Right();
161  break;
162  }
163  }
164  pPorIter = pPorIter->GetNextPortion();
165  }
166  }
167  if( !bEndPor && nTmpLeft >= nMaxRight )
168  return;
169 
170  // DropCaps!
171  // 7538: of course for the printer, too
172  if( !bPaintDrop )
173  {
174  // 8084: Optimization, less painting
175  // AMA: By 8084 7538 has been revived
176  // bDrawInWindow removed, so that DropCaps also can be printed
177  bPaintDrop = pPor == m_pCurr->GetFirstPortion()
178  && GetDropLines() >= GetLineNr();
179  }
180 
181  sal_uInt16 nTmpHeight, nTmpAscent;
182  CalcAscentAndHeight( nTmpAscent, nTmpHeight );
183 
184  // bClip decides if there's a need to clip
185  // The whole thing must be done before retouching
186 
187  bool bClip = ( bDrawInWindow || bUnderSized ) && !rClip.IsChg();
188  if( bClip && pPor )
189  {
190  // If TopLeft or BottomLeft of the line are outside, the we must clip.
191  // The check for Right() is done in the output loop ...
192 
193  if( GetInfo().GetPos().X() < rPaint.Left() ||
194  GetInfo().GetPos().Y() < rPaint.Top() ||
195  GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
196  {
197  bClip = false;
198  rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
199  }
200 #if OSL_DEBUG_LEVEL > 1
201  static bool bClipAlways = false;
202  if( bClip && bClipAlways )
203  { bClip = false;
204  rClip.ChgClip( rPaint );
205  }
206 #endif
207  }
208 
209  // Alignment
211  Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
212  if ( aPnt1.X() < rPaint.Left() )
213  aPnt1.setX( rPaint.Left() );
214  if ( aPnt1.Y() < rPaint.Top() )
215  aPnt1.setY( rPaint.Top() );
216  Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
217  GetInfo().GetPos().Y() + nTmpHeight );
218  if ( aPnt2.X() > rPaint.Right() )
219  aPnt2.setX( rPaint.Right() );
220  if ( aPnt2.Y() > rPaint.Bottom() )
221  aPnt2.setY( rPaint.Bottom() );
222 
223  const SwRect aLineRect( aPnt1, aPnt2 );
224 
225  if( m_pCurr->IsClipping() )
226  {
227  const SwTextFrame& rFrame = *GetInfo().GetTextFrame();
228  // tdf#117448 at small fixed line height, enlarge clipping area in table cells
229  // to show previously clipped text content on the area of paragraph margins
230  if ( rFrame.IsInTab() )
231  rClip.ChgClip( aLineRect, m_pFrame, false, rFrame.GetTopMargin(), rFrame.GetBottomMargin() );
232  else
233  rClip.ChgClip( aLineRect, m_pFrame );
234  bClip = false;
235  }
236 
237  if( !pPor && !bEndPor )
238  return;
239 
240  // Baseline output also if non-TextPortion (compare TabPor with Fill)
241  // if no special vertical alignment is used,
242  // we calculate Y value for the whole line
243  SwTextGridItem const*const pGrid(GetGridItem(GetTextFrame()->FindPageFrame()));
244  const bool bAdjustBaseLine =
245  GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) ||
246  ( nullptr != pGrid );
247  const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
248  if ( ! bAdjustBaseLine )
249  GetInfo().Y( nLineBaseLine );
250 
251  // 7529: Pre-paint post-its
252  if( GetInfo().OnWin() && pPor && !pPor->Width() )
253  {
254  SeekAndChg( GetInfo() );
255 
256  if( bAdjustBaseLine )
257  {
258  const SwTwips nOldY = GetInfo().Y();
259 
260  GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, nullptr,
261  GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
262  GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
263  ) );
264 
265  pPor->PrePaint( GetInfo(), pPor );
266  GetInfo().Y( nOldY );
267  }
268  else
269  pPor->PrePaint( GetInfo(), pPor );
270  }
271 
272  // 7923: EndPortions output chars, too, that's why we change the font
273  if( bEndPor )
275 
276  const bool bRest = m_pCurr->IsRest();
277  bool bFirst = true;
278 
279  SwArrowPortion *pArrow = nullptr;
280  // Reference portion for the paragraph end portion
281  SwLinePortion* pEndTempl = m_pCurr->GetFirstPortion();
282 
283  while( pPor )
284  {
285  bool bSeeked = true;
286  GetInfo().SetLen( pPor->GetLen() );
287 
288  const SwTwips nOldY = GetInfo().Y();
289 
290  if ( bAdjustBaseLine )
291  {
292  GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, pPor ) );
293 
294  // we store the last portion, because a possible paragraph
295  // end character has the same font as this portion
296  // (only in special vertical alignment case, otherwise the first
297  // portion of the line is used)
298  if ( pPor->Width() && pPor->InTextGrp() )
299  pEndTempl = pPor;
300  }
301 
302  // set redlining for line break symbol
303  if ( pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() && GetRedln() )
304  {
305  SeekAndChg( GetInfo() );
306  if ( m_pCurr->GetRedlineEndType() != RedlineType::None )
307  static_cast<SwBreakPortion&>(*pPor).SetRedline( m_pCurr->GetRedlineEndType() );
308  }
309 
310  // A special case are GluePortions which output blanks.
311 
312  // 6168: Avoid that the rest of a FieldPortion gets the attributes of the
313  // next portion with SeekAndChgBefore():
314  if( bRest && pPor->InFieldGrp() && !pPor->GetLen() )
316  else if ( pPor->IsQuoVadisPortion() )
317  {
318  // A remark on QuoVadis/ErgoSum:
319  // We use the Font set for the Paragraph for these portions.
320  // Thus, we initialize:
321  TextFrameIndex nOffset = GetInfo().GetIdx();
322  SeekStartAndChg( GetInfo(), true );
323  if( GetRedln() && m_pCurr->HasRedline() )
324  {
325  std::pair<SwTextNode const*, sal_Int32> const pos(
326  GetTextFrame()->MapViewToModel(nOffset));
327  GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
328  }
329  }
330  else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
331  SeekAndChg( GetInfo() );
332  else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
333  {
334  // Paragraph symbols should have the same font as the paragraph in front of them,
335  // except for the case that there's redlining in the paragraph
336  if( GetRedln() )
337  SeekAndChg( GetInfo() );
338  else
340  }
341  else
342  bSeeked = false;
343 
344  // bRest = false;
345 
346  // If the end of the portion juts out, it is clipped.
347  // A safety distance of half the height is added, so that
348  // TTF-"f" isn't overlapping into the page margin.
349  if( bClip &&
350  GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
351  {
352  bClip = false;
353  rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
354  }
355 
356  // Portions, which lay "below" the text like post-its
357  SwLinePortion *pNext = pPor->GetNextPortion();
358  if( GetInfo().OnWin() && pNext && !pNext->Width() )
359  {
360  // Fix 11289: Fields were omitted here because of Last!=Owner during
361  // loading Brief.sdw. Now the fields are allowed again,
362  // by bSeeked Last!=Owner is being avoided.
363  if ( !bSeeked )
364  SeekAndChg( GetInfo() );
365  pNext->PrePaint( GetInfo(), pPor );
366  }
367 
368  // We calculate a separate font for underlining.
369  CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
370  SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
371  if ( pUnderLineFnt )
372  {
373  const Point aTmpPoint( GetInfo().X(),
374  bAdjustBaseLine ?
375  pUnderLineFnt->GetPos().Y() :
376  nLineBaseLine );
377  pUnderLineFnt->SetPos( aTmpPoint );
378  }
379 
380  // in extended input mode we do not want a common underline font.
381  SwUnderlineFont* pOldUnderLineFnt = nullptr;
382  if ( GetRedln() && GetRedln()->ExtOn() )
383  {
384  pOldUnderLineFnt = GetInfo().GetUnderFnt();
385  GetInfo().SetUnderFnt( nullptr );
386  }
387 
388  {
389  // #i16816# tagged pdf support
390  Por_Info aPorInfo( *pPor, *this );
391  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut );
392 
393  if( pPor->IsMultiPortion() )
394  PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) );
395  else
396  pPor->Paint( GetInfo() );
397  }
398 
399  // reset underline font
400  if ( pOldUnderLineFnt )
401  GetInfo().SetUnderFnt( pOldUnderLineFnt );
402 
403  // reset (for special vertical alignment)
404  GetInfo().Y( nOldY );
405 
406  bFirst &= !pPor->GetLen();
407  if( pNext || !pPor->IsMarginPortion() )
408  pPor->Move( GetInfo() );
409  if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
410  pArrow = static_cast<SwArrowPortion*>(pPor);
411 
412  pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
413  // #i16816# tagged pdf support
414  ( GetInfo().GetVsh() &&
416  pNext && pNext->IsHolePortion() ) ?
417  pNext :
418  nullptr;
419  }
420 
421  // delete underline font
422  delete GetInfo().GetUnderFnt();
423  GetInfo().SetUnderFnt( nullptr );
424 
425  // paint remaining stuff
426  if( bDrawInWindow )
427  {
428  // If special vertical alignment is enabled, GetInfo().Y() is the
429  // top of the current line. Therefore is has to be adjusted for
430  // the painting of the remaining stuff. We first store the old value.
431  const SwTwips nOldY = GetInfo().Y();
432 
433  if( !GetNextLine() &&
434  GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
435  GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() &&
436  GetInfo().GetIdx() >= TextFrameIndex(GetInfo().GetText().getLength()))
437  {
438  bool bHasRedlineEnd( GetRedln() && m_pCurr->HasRedlineEnd() );
439  RedlineType eRedlineEnd = bHasRedlineEnd ? m_pCurr->GetRedlineEndType() : RedlineType::None;
440  if( bHasRedlineEnd )
441  {
442  TextFrameIndex nOffset = GetInfo().GetIdx();
443  SeekStartAndChg( GetInfo(), true );
444  std::pair<SwTextNode const*, sal_Int32> const pos(
445  GetTextFrame()->MapViewToModel(nOffset));
446  GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
447  }
448  const SwTmpEndPortion aEnd( *pEndTempl,
449  bHasRedlineEnd && eRedlineEnd != RedlineType::Delete ? m_pFont->GetUnderline() : LINESTYLE_NONE,
450  bHasRedlineEnd && eRedlineEnd == RedlineType::Delete ? m_pFont->GetStrikeout() : STRIKEOUT_NONE,
451  bHasRedlineEnd ? m_pFont->GetColor() : COL_AUTO );
452  GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
453 
454  if ( bAdjustBaseLine )
455  GetInfo().Y( GetInfo().GetPos().Y()
456  + AdjustBaseLine( *m_pCurr, &aEnd ) );
457  GetInfo().X( GetInfo().X() +
458  ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) );
459  aEnd.Paint( GetInfo() );
460  GetInfo().Y( nOldY );
461  }
462  if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
463  {
464  const bool bNextUndersized =
465  ( GetTextFrame()->GetNext() &&
466  0 == GetTextFrame()->GetNext()->getFramePrintArea().Height() &&
467  GetTextFrame()->GetNext()->IsTextFrame() &&
468  static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ;
469 
470  if( bUnderSized || bNextUndersized )
471  {
472  if ( bAdjustBaseLine )
473  GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() );
474 
475  // Left arrow (text overflowing)
476  if( pArrow )
477  GetInfo().DrawRedArrow( *pArrow );
478 
479  // GetInfo().Y() must be current baseline
480  SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom();
481  if( ( nDiff > 0 &&
482  (GetEnd() < TextFrameIndex(GetInfo().GetText().getLength()) ||
483  ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
484  (nDiff >= 0 && bNextUndersized) )
485 
486  {
487  // Right arrow (text overflowing)
488  SwArrowPortion aArrow( GetInfo() );
489  GetInfo().DrawRedArrow( aArrow );
490  }
491 
492  GetInfo().Y( nOldY );
493  }
494  }
495  }
496 
497  if( m_pCurr->IsClipping() )
498  rClip.ChgClip( rPaint, m_pFrame );
499 }
500 
502  tools::Long nAdjustBaseLine )
503 {
504  // Check if common underline should not be continued
505  if ( IsUnderlineBreak( *pPor, *m_pFont ) )
506  {
507  // delete underline font
508  delete GetInfo().GetUnderFnt();
509  GetInfo().SetUnderFnt( nullptr );
510  return;
511  }
512  // Reuse calculated underline font as much as possible.
513  if (GetInfo().GetUnderFnt() &&
514  GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + TextFrameIndex(1))
515  {
516  SwFont &rFont = GetInfo().GetUnderFnt()->GetFont();
517  const Color aColor = GetUnderColor( GetInfo().GetFont() );
518  if ( GetUnderColor( &rFont ) != aColor )
519  rFont.SetColor( aColor );
520  return;
521  }
522 
523  // If current underline matches the common underline font, we continue
524  // to use the common underline font.
525  // Bug 120769:Color of underline display wrongly
526  if ( GetInfo().GetUnderFnt() &&
527  GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
528  GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != COL_AUTO )
529  return;
530  //Bug 120769(End)
531 
532  OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(),
533  "CheckSpecialUnderline without underlined font" );
534  MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) );
535  const SwFont* pParaFnt = GetAttrHandler().GetFont();
536  if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
537  aUnderMulti.SelectAll();
538 
539  if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
540  {
541  // first, add the paragraph properties to MultiSelection - if there are
542  // Hints too, they will override the positions if they're added later
543  sal_Int32 nTmp(0);
544  for (auto const& e : pMerged->extents)
545  {
546  const SfxPoolItem* pItem;
547  if (SfxItemState::SET == e.pNode->GetSwAttrSet().GetItemState(
548  RES_CHRATR_UNDERLINE, true, &pItem))
549  {
550  const bool bUnderSelect(m_pFont->GetUnderline() ==
551  static_cast<SvxUnderlineItem const*>(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() &&
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: */
SwAttrHandler & GetAttrHandler()
Definition: itratr.hxx:109
std::deque< sal_uInt16 > * GetpKanaComp() const
Definition: porlay.hxx:203
void Move(SwTextPaintInfo &rInf)
Definition: porlin.cxx:268
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:151
void SetUnderFnt(SwUnderlineFont *pNew)
Definition: inftxt.hxx:235
void Right(const tools::Long nRight)
Definition: swrect.hxx:200
SwViewShell * GetVsh()
Definition: inftxt.hxx:221
void GetAdjusted() const
Definition: itrtxt.hxx:250
sal_uInt16 GetLineNr() const
Definition: itrtxt.hxx:87
bool IsClipping() const
Definition: porlay.hxx:155
bool ChkSpecialUnderline() const
Definition: redlnitr.hxx:118
bool InSpaceGrp() const
Definition: porlin.hxx:109
bool IsRest() const
Definition: porlay.hxx:130
sal_uInt16 Height() const
Definition: possiz.hxx:50
bool SeekStartAndChg(SwTextSizeInfo &rInf, const bool bPara=false)
Definition: itrtxt.hxx:323
bool IsUnderlineBreak(const SwLinePortion &rPor, const SwFont &rFnt)
Definition: itrpaint.cxx:46
TextFrameIndex GetStart() const
Definition: itrtxt.hxx:88
const Color & GetUnderColor() const
Definition: swfont.hxx:269
void SetPos(const Point &rNew)
Definition: inftxt.hxx:429
void Left(const tools::Long nLeft)
Definition: swrect.hxx:195
virtual tools::Long CalcSpacing(tools::Long nSpaceAdd, const SwTextSizeInfo &rInf) const
Definition: porlin.cxx:305
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
Extracts pool item of type nWhich from rAttr.
Definition: atrstck.cxx:156
void CtorInitTextPainter(SwTextFrame *pFrame, SwTextPaintInfo *pInf)
Definition: itrpaint.cxx:63
sal_uIntPtr sal_uLong
long Long
void SetFillColor(const Color &rColor)
Definition: swfont.hxx:433
const SwRect & getFramePrintArea() const
Definition: frame.hxx:179
tools::Long GetLen(const Point &rPnt)
short Seek(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew, sal_Int32 nOld)
Definition: redlnitr.cxx:671
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
SwFont * m_pFont
Definition: itratr.hxx:39
bool SeekAndChg(SwTextSizeInfo &rInf)
Definition: itrtxt.hxx:310
bool Select(sal_Int32 nIndex, bool bSelect=true)
tools::Long GetSpaceAdd() const
Definition: inftxt.hxx:440
const Size & GetSize(SwFontScript nWhich) const
Definition: swfont.hxx:204
FontStrikeout GetStrikeout() const
Definition: swfont.hxx:272
void SetKanaComp(std::deque< sal_uInt16 > *pNew)
Definition: inftxt.hxx:322
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
bool InFieldGrp() const
Definition: porlin.hxx:104
RedlineType GetRedlineEndType() const
Definition: porlay.hxx:140
SwTwips Y() const
Definition: itrtxt.hxx:90
sal_Int32 GetRangeCount() const
bool HasRedlineEnd() const
Definition: porlay.hxx:138
bool Seek(TextFrameIndex nPos)
Enables the attributes used at char pos nPos in the logical font.
Definition: itratr.cxx:301
SwTextAttr const * NextAttr(SwTextNode const **ppNode=nullptr)
Definition: txtfrm.cxx:85
void SetColor(const Color &rColor)
Definition: swfont.hxx:411
WEIGHT_BOLD
const SwFont * GetFont() const
Definition: atrhndl.hxx:112
bool IsMarginPortion() const
Definition: porlin.hxx:124
constexpr::Color COL_AUTO(0xFF, 0xFF, 0xFF, 0xFF)
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
virtual void Paint(const SwTextPaintInfo &rInf) const =0
LINESTYLE_NONE
bool IsBreakPortion() const
Definition: porlin.hxx:114
const SwRect & getFrameArea() const
Definition: frame.hxx:178
size_t pos
#define X
bool IsInTab() const
Definition: frame.hxx:936
SwTwips Right() const
Definition: itrtxt.hxx:181
SwTextPaintInfo & GetInfo()
Definition: itrpaint.hxx:57
bool IsTextFrame() const
Definition: frame.hxx:1215
const SwLineLayout * GetNextLine() const
Definition: itrtxt.cxx:134
oslFileHandle & pOut
SvxCaseMap GetCaseMap() const
Definition: swfont.hxx:276
Describes parts of multiple text nodes, which will form a text frame, even when redlines are hidden a...
Definition: txtfrm.hxx:947
void ChgPhysFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.cxx:962
void SetStrikeout(const FontStrikeout eStrikeout)
Definition: swfont.hxx:572
SwFontScript GetActual() const
Definition: swfont.hxx:182
void SetPaintOfst(const SwTwips nNew)
Definition: inftxt.hxx:735
SwTwips Y() const
Definition: inftxt.hxx:380
bool bPaintDrop
Definition: itrpaint.hxx:29
void CalcAscentAndHeight(sal_uInt16 &rAscent, sal_uInt16 &rHeight) const
Definition: itrtxt.cxx:63
const SwViewOption & GetOpt() const
Definition: inftxt.hxx:238
void PaintMultiPortion(const SwRect &rPaint, SwMultiPortion &rMulti, const SwMultiPortion *pEnvPor=nullptr)
Definition: pormulti.cxx:1497
SwTextInfo * m_pInf
Definition: itrtxt.hxx:35
sal_uInt16 AdjustBaseLine(const SwLineLayout &rLine, const SwLinePortion *pPor, sal_uInt16 nPorHeight=0, sal_uInt16 nAscent=0, const bool bAutoToCentered=false) const
Definition: itrtxt.cxx:214
SwLinePortion * CalcPaintOfst(const SwRect &rPaint)
Definition: itrpaint.cxx:72
const SwLineLayout * GetPrevLine()
Definition: itrtxt.cxx:144
int i
const SwLineInfo & GetLineInfo() const
Definition: itrtxt.hxx:128
const Point & GetPos() const
Definition: swfont.hxx:967
vcl::RenderContext * GetOut()
Definition: inftxt.hxx:224
void SetFont(SwFont *pNew)
Definition: inftxt.hxx:233
SwParaPortion * GetParaPortion()
Definition: inftxt.hxx:121
bool IsFlyPortion() const
Definition: porlin.hxx:125
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1175
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2566
SwLinePortion * GetFirstPortion() const
Definition: porlay.cxx:699
bool IsParagraph(bool bHard=false) const
Definition: viewopt.hxx:233
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(MergedPara const &, TextFrameIndex nIndex)
Definition: txtfrm.cxx:1156
SwFont & GetFont()
Definition: swfont.hxx:962
TextFrameIndex GetEnd() const
Definition: swfont.hxx:968
tools::Long Width() const
WEIGHT_NORMAL
void ResetSpaceIdx()
Definition: inftxt.hxx:436
void SetEscapement(const short nNewEsc)
Definition: swfont.hxx:781
sal_uInt16 GetTabPos() const
Definition: portab.hxx:39
static Color GetUnderColor(const SwFont *pFont)
Definition: itrpaint.cxx:57
SwFont * GetFnt()
Definition: itratr.hxx:103
TextFrameIndex GetIdx() const
Definition: inftxt.hxx:271
void SetWeight(const FontWeight eWeight, const SwFontScript nWhich)
Definition: swfont.hxx:529
bool IsPDFExport() const
Definition: viewopt.hxx:403
tools::Long GetBottomMargin() const
Definition: ssfrm.cxx:42
void PrePaint(const SwTextPaintInfo &rInf, const SwLinePortion *pLast) const
Definition: porlin.cxx:76
const Color & GetColor() const
Definition: swfont.hxx:273
TextFrameIndex GetLen() const
Definition: porlin.hxx:74
void SetPos(const Point &rPoint)
Definition: swfont.hxx:970
bool InTabGrp() const
Definition: porlin.hxx:100
SwTextFrame * GetTextFrame()
Definition: inftxt.hxx:284
Point GetTopLeft() const
Definition: itrtxt.hxx:186
tools::Long SwTwips
Definition: swtypes.hxx:49
const OUString & GetText() const
Definition: inftxt.hxx:239
const Range & GetRange(sal_Int32 nRange) const
bool IsHolePortion() const
Definition: porlin.hxx:126
tools::Long Min() const
SwUnderlineFont * GetUnderFnt() const
Definition: inftxt.hxx:236
const Point & GetPos() const
Definition: inftxt.hxx:428
bool IsMultiPortion() const
Definition: porlin.hxx:134
FontLineStyle GetUnderline() const
Definition: swfont.hxx:268
FontLineStyle GetLineStyle() const
SwTwips X() const
Definition: inftxt.hxx:378
SwTextFrame * m_pFrame
Definition: itrtxt.hxx:34
Base class for anything that can be part of a line in the Writer layout.
Definition: porlin.hxx:50
void CtorInitTextCursor(SwTextFrame *pFrame, SwTextSizeInfo *pInf)
Definition: itrcrsr.cxx:392
bool SeekAndChgBefore(SwTextSizeInfo &rInf)
Definition: itrtxt.hxx:315
void Bottom(const tools::Long nBottom)
Definition: swrect.hxx:209
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
FontWeight GetWeight() const
Definition: swfont.hxx:281
void ChgClip(const SwRect &rRect, const SwTextFrame *pFrame=nullptr, bool bEnlargeRect=false, sal_Int32 nEnlargeTop=0, sal_Int32 nEnlargeBottom=0)
Definition: txtpaint.hxx:47
void SetLen(const TextFrameIndex nNew)
Definition: inftxt.hxx:274
void SetSize(const Size &rSize, const SwFontScript nWhich)
Definition: swfont.hxx:734
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:423
bool HasSpecialAlign(bool bVert) const
Definition: inftxt.hxx:86
bool OnWin() const
Definition: inftxt.hxx:192
void Top(const tools::Long nTop)
Definition: swrect.hxx:204
bool InTextGrp() const
Definition: porlin.hxx:98
sal_uInt16 Width() const
Definition: possiz.hxx:52
SwScriptInfo & GetScriptInfo()
Definition: porlay.hxx:289
SwFontScript
Definition: swfont.hxx:122
double getLength(const B2DPolygon &rCandidate)
void SetpSpaceAdd(std::vector< tools::Long > *pNew)
Definition: inftxt.hxx:444
tools::Long GetTopMargin() const
Definition: ssfrm.cxx:40
void DrawRedArrow(const SwLinePortion &rPor) const
Definition: inftxt.cxx:1017
bool IsChg() const
Definition: txtpaint.hxx:54
const SwLineLayout * GetCurr() const
Definition: itrtxt.hxx:83
bool HasRedline() const
Definition: porlay.hxx:136
RedlineType
bool IsArrowPortion() const
Definition: porlin.hxx:133
SwTextFrame * GetTextFrame()
Definition: itrtxt.hxx:134
void ResetKanaIdx()
Definition: inftxt.hxx:319
bool IsWordLineMode() const
Definition: swfont.hxx:274
SwLineLayout * m_pCurr
Definition: itrtxt.hxx:36
STRIKEOUT_NONE
void CheckSpecialUnderline(const SwLinePortion *pPor, tools::Long nAdjustBaseLine=0)
Definition: itrpaint.cxx:501
TextFrameIndex GetEnd() const
Definition: itrtxt.hxx:89
sal_uInt16 GetDropLines() const
Definition: itrtxt.hxx:202
bool IsQuoVadisPortion() const
Definition: porlin.hxx:116
void SelectAll(bool bSelect=true)
std::vector< tools::Long > * GetpLLSpaceAdd() const
Definition: porlay.hxx:198
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:762
SwLinePortion * GetNextPortion() const
Definition: porlin.hxx:72
tools::Long Max() const
void SetIdx(const TextFrameIndex nNew)
Definition: inftxt.hxx:272
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...
short GetEscapement() const
Definition: swfont.hxx:275
void Height(tools::Long nNew)
Definition: swrect.hxx:191
void SetOverline(const FontLineStyle eOverline)
Definition: swfont.hxx:557
bool IsFlyCntPortion() const
Definition: porlin.hxx:112
tools::Long GetHeight() const
Definition: swfont.hxx:280
sal_uInt16 & GetAscent()
Definition: porlin.hxx:77
SwRedlineItr * GetRedln()
Definition: itratr.hxx:81
bool HasUnderscore() const
Definition: porlay.hxx:148
void DrawTextLine(const SwRect &rPaint, SwSaveClip &rClip, const bool bUnderSz)
Definition: itrpaint.cxx:120
bool IsPostItsPortion() const
Definition: porlin.hxx:128
SwFrame * GetNext()
Definition: frame.hxx:659