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  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( 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  // A special case are GluePortions which output blanks.
303 
304  // 6168: Avoid that the rest of a FieldPortion gets the attributes of the
305  // next portion with SeekAndChgBefore():
306  if( bRest && pPor->InFieldGrp() && !pPor->GetLen() )
308  else if ( pPor->IsQuoVadisPortion() )
309  {
310  // A remark on QuoVadis/ErgoSum:
311  // We use the Font set for the Paragraph for these portions.
312  // Thus, we initialize:
313  TextFrameIndex nOffset = GetInfo().GetIdx();
314  SeekStartAndChg( GetInfo(), true );
315  if( GetRedln() && m_pCurr->HasRedline() )
316  {
317  std::pair<SwTextNode const*, sal_Int32> const pos(
318  GetTextFrame()->MapViewToModel(nOffset));
319  GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
320  }
321  }
322  else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
323  SeekAndChg( GetInfo() );
324  else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
325  {
326  // Paragraph symbols should have the same font as the paragraph in front of them,
327  // except for the case that there's redlining in the paragraph
328  if( GetRedln() )
329  SeekAndChg( GetInfo() );
330  else
332  }
333  else
334  bSeeked = false;
335 
336  // bRest = false;
337 
338  // If the end of the portion juts out, it is clipped.
339  // A safety distance of half the height is added, so that
340  // TTF-"f" isn't overlapping into the page margin.
341  if( bClip &&
342  GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
343  {
344  bClip = false;
345  rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
346  }
347 
348  // Portions, which lay "below" the text like post-its
349  SwLinePortion *pNext = pPor->GetNextPortion();
350  if( GetInfo().OnWin() && pNext && !pNext->Width() )
351  {
352  // Fix 11289: Fields were omitted here because of Last!=Owner during
353  // loading Brief.sdw. Now the fields are allowed again,
354  // by bSeeked Last!=Owner is being avoided.
355  if ( !bSeeked )
356  SeekAndChg( GetInfo() );
357  pNext->PrePaint( GetInfo(), pPor );
358  }
359 
360  // We calculate a separate font for underlining.
361  CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
362  SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
363  if ( pUnderLineFnt )
364  {
365  const Point aTmpPoint( GetInfo().X(),
366  bAdjustBaseLine ?
367  pUnderLineFnt->GetPos().Y() :
368  nLineBaseLine );
369  pUnderLineFnt->SetPos( aTmpPoint );
370  }
371 
372  // in extended input mode we do not want a common underline font.
373  SwUnderlineFont* pOldUnderLineFnt = nullptr;
374  if ( GetRedln() && GetRedln()->ExtOn() )
375  {
376  pOldUnderLineFnt = GetInfo().GetUnderFnt();
377  GetInfo().SetUnderFnt( nullptr );
378  }
379 
380  {
381  // #i16816# tagged pdf support
382  Por_Info aPorInfo( *pPor, *this );
383  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut );
384 
385  if( pPor->IsMultiPortion() )
386  PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) );
387  else
388  pPor->Paint( GetInfo() );
389  }
390 
391  // reset underline font
392  if ( pOldUnderLineFnt )
393  GetInfo().SetUnderFnt( pOldUnderLineFnt );
394 
395  // reset (for special vertical alignment)
396  GetInfo().Y( nOldY );
397 
398  bFirst &= !pPor->GetLen();
399  if( pNext || !pPor->IsMarginPortion() )
400  pPor->Move( GetInfo() );
401  if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
402  pArrow = static_cast<SwArrowPortion*>(pPor);
403 
404  pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
405  // #i16816# tagged pdf support
406  ( GetInfo().GetVsh() &&
408  pNext && pNext->IsHolePortion() ) ?
409  pNext :
410  nullptr;
411  }
412 
413  // delete underline font
414  delete GetInfo().GetUnderFnt();
415  GetInfo().SetUnderFnt( nullptr );
416 
417  // paint remaining stuff
418  if( bDrawInWindow )
419  {
420  // If special vertical alignment is enabled, GetInfo().Y() is the
421  // top of the current line. Therefore is has to be adjusted for
422  // the painting of the remaining stuff. We first store the old value.
423  const SwTwips nOldY = GetInfo().Y();
424 
425  if( !GetNextLine() &&
426  GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
427  GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() &&
428  GetInfo().GetIdx() >= TextFrameIndex(GetInfo().GetText().getLength()))
429  {
430  const SwTmpEndPortion aEnd( *pEndTempl );
431  GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
432 
433  if ( bAdjustBaseLine )
434  GetInfo().Y( GetInfo().GetPos().Y()
435  + AdjustBaseLine( *m_pCurr, &aEnd ) );
436  GetInfo().X( GetInfo().X() +
437  ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) );
438  aEnd.Paint( GetInfo() );
439  GetInfo().Y( nOldY );
440  }
441  if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
442  {
443  const bool bNextUndersized =
444  ( GetTextFrame()->GetNext() &&
445  0 == GetTextFrame()->GetNext()->getFramePrintArea().Height() &&
446  GetTextFrame()->GetNext()->IsTextFrame() &&
447  static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ;
448 
449  if( bUnderSized || bNextUndersized )
450  {
451  if ( bAdjustBaseLine )
452  GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() );
453 
454  // Left arrow (text overflowing)
455  if( pArrow )
456  GetInfo().DrawRedArrow( *pArrow );
457 
458  // GetInfo().Y() must be current baseline
459  SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom();
460  if( ( nDiff > 0 &&
461  (GetEnd() < TextFrameIndex(GetInfo().GetText().getLength()) ||
462  ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
463  (nDiff >= 0 && bNextUndersized) )
464 
465  {
466  // Right arrow (text overflowing)
467  SwArrowPortion aArrow( GetInfo() );
468  GetInfo().DrawRedArrow( aArrow );
469  }
470 
471  GetInfo().Y( nOldY );
472  }
473  }
474  }
475 
476  if( m_pCurr->IsClipping() )
477  rClip.ChgClip( rPaint, m_pFrame );
478 }
479 
481  long nAdjustBaseLine )
482 {
483  // Check if common underline should not be continued
484  if ( IsUnderlineBreak( *pPor, *m_pFont ) )
485  {
486  // delete underline font
487  delete GetInfo().GetUnderFnt();
488  GetInfo().SetUnderFnt( nullptr );
489  return;
490  }
491  // Reuse calculated underline font as much as possible.
492  if (GetInfo().GetUnderFnt() &&
493  GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + TextFrameIndex(1))
494  {
495  SwFont &rFont = GetInfo().GetUnderFnt()->GetFont();
496  const Color aColor = GetUnderColor( GetInfo().GetFont() );
497  if ( GetUnderColor( &rFont ) != aColor )
498  rFont.SetColor( aColor );
499  return;
500  }
501 
502  // If current underline matches the common underline font, we continue
503  // to use the common underline font.
504  // Bug 120769:Color of underline display wrongly
505  if ( GetInfo().GetUnderFnt() &&
506  GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
507  GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != COL_AUTO )
508  return;
509  //Bug 120769(End)
510 
511  OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(),
512  "CheckSpecialUnderline without underlined font" );
513  MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) );
514  const SwFont* pParaFnt = GetAttrHandler().GetFont();
515  if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
516  aUnderMulti.SelectAll();
517 
518  if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
519  {
520  // first, add the paragraph properties to MultiSelection - if there are
521  // Hints too, they will override the positions if they're added later
522  sal_Int32 nTmp(0);
523  for (auto const& e : pMerged->extents)
524  {
525  const SfxPoolItem* pItem;
526  if (SfxItemState::SET == e.pNode->GetSwAttrSet().GetItemState(
527  RES_CHRATR_UNDERLINE, true, &pItem))
528  {
529  const bool bUnderSelect(m_pFont->GetUnderline() ==
530  static_cast<SvxUnderlineItem const*>(pItem)->GetLineStyle());
531  aUnderMulti.Select(Range(nTmp, nTmp + e.nEnd - e.nStart - 1),
532  bUnderSelect);
533  }
534  nTmp += e.nEnd - e.nStart;
535  }
536  }
537 
538  SwTextNode const* pNode(nullptr);
540  for (SwTextAttr const* pTextAttr = iter.NextAttr(&pNode); pTextAttr;
541  pTextAttr = iter.NextAttr(&pNode))
542  {
543  SvxUnderlineItem const*const pItem =
545 
546  if (pItem)
547  {
548  TextFrameIndex const nStart(
549  GetTextFrame()->MapModelToView(pNode, pTextAttr->GetStart()));
550  TextFrameIndex const nEnd(
551  GetTextFrame()->MapModelToView(pNode, *pTextAttr->End()));
552  if (nEnd > nStart)
553  {
554  const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
555  aUnderMulti.Select(Range(sal_Int32(nStart), sal_Int32(nEnd) - 1),
556  bUnderSelect);
557  }
558  }
559  }
560 
561  const TextFrameIndex nIndx = GetInfo().GetIdx();
562  TextFrameIndex nUnderEnd(0);
563  const size_t nCnt = aUnderMulti.GetRangeCount();
564 
565  // find the underline range the current portion is contained in
566  for( size_t i = 0; i < nCnt; ++i )
567  {
568  const Range& rRange = aUnderMulti.GetRange( i );
569  if (nUnderEnd == TextFrameIndex(rRange.Min()))
570  nUnderEnd = TextFrameIndex(rRange.Max());
571  else if (nIndx >= TextFrameIndex(rRange.Min()))
572  {
573  nUnderEnd = TextFrameIndex(rRange.Max());
574  }
575  else
576  break;
577  }
578 
579  if ( GetEnd() && GetEnd() <= nUnderEnd )
580  nUnderEnd = GetEnd() - TextFrameIndex(1);
581 
582  // calculate the new common underline font
583  SwFont* pUnderlineFnt = nullptr;
584  Point aCommonBaseLine;
585 
586  // check, if underlining is not isolated
587  if (nIndx + GetInfo().GetLen() < nUnderEnd + TextFrameIndex(1))
588  {
589  // here starts the algorithm for calculating the underline font
590  SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
591  SwAttrIter aIter(*GetInfo().GetTextFrame()->GetTextNodeFirst(),
592  rScriptInfo, GetTextFrame());
593 
594  TextFrameIndex nTmpIdx = nIndx;
595  sal_uLong nSumWidth = 0;
596  sal_uLong nSumHeight = 0;
597  sal_uLong nBold = 0;
598  sal_uInt16 nMaxBaseLineOfst = 0;
599  int nNumberOfPortions = 0;
600 
601  while (nTmpIdx <= nUnderEnd && pPor)
602  {
603  if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
604  pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
605  pPor->IsHolePortion() ||
606  ( pPor->IsMultiPortion() && ! static_cast<const SwMultiPortion*>(pPor)->IsBidi() ) )
607  break;
608 
609  aIter.Seek( nTmpIdx );
610  if ( aIter.GetFnt()->GetEscapement() < 0 || m_pFont->IsWordLineMode() ||
611  SvxCaseMap::SmallCaps == m_pFont->GetCaseMap() )
612  break;
613 
614  if ( !aIter.GetFnt()->GetEscapement() )
615  {
616  nSumWidth += pPor->Width();
617  const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
618 
619  // If we do not have a common baseline we take the baseline
620  // and the font of the lowest portion.
621  if ( nAdjustBaseLine )
622  {
623  const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *m_pCurr, pPor );
624  if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
625  {
626  nMaxBaseLineOfst = nTmpBaseLineOfst;
627  nSumHeight = nFontHeight;
628  }
629  }
630  // in horizontal layout we build a weighted sum of the heights
631  else
632  nSumHeight += pPor->Width() * nFontHeight;
633 
634  if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
635  nBold += pPor->Width();
636  }
637 
638  ++nNumberOfPortions;
639 
640  nTmpIdx += pPor->GetLen();
641  pPor = pPor->GetNextPortion();
642  }
643 
644  // resulting height
645  if ( nNumberOfPortions > 1 && nSumWidth )
646  {
647  const sal_uLong nNewFontHeight = nAdjustBaseLine ?
648  nSumHeight :
649  nSumHeight / nSumWidth;
650 
651  pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
652 
653  // font height
654  const SwFontScript nActual = pUnderlineFnt->GetActual();
655  pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
656  nNewFontHeight ), nActual );
657 
658  // font weight
659  if ( 2 * nBold > nSumWidth )
660  pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
661  else
662  pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
663 
664  // common base line
665  aCommonBaseLine.setY( nAdjustBaseLine + nMaxBaseLineOfst );
666  }
667  }
668 
669  // an escaped redlined portion should also have a special underlining
670  if( ! pUnderlineFnt && m_pFont->GetEscapement() > 0 && GetRedln() &&
672  pUnderlineFnt = new SwFont( *m_pFont );
673 
674  delete GetInfo().GetUnderFnt();
675 
676  if ( pUnderlineFnt )
677  {
678  pUnderlineFnt->SetProportion( 100 );
679  pUnderlineFnt->SetEscapement( 0 );
680  pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
681  pUnderlineFnt->SetOverline( LINESTYLE_NONE );
682  const Color aFillColor( COL_TRANSPARENT );
683  pUnderlineFnt->SetFillColor( aFillColor );
684 
685  GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt, nUnderEnd,
686  aCommonBaseLine ) );
687  }
688  else
689  // I'm sorry, we do not have a special underlining font for you.
690  GetInfo().SetUnderFnt( nullptr );
691 }
692 
693 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwAttrHandler & GetAttrHandler()
Definition: itratr.hxx:109
long Width() const
std::deque< sal_uInt16 > * GetpKanaComp() const
Definition: porlay.hxx:184
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:242
SwViewShell * GetVsh()
Definition: inftxt.hxx:228
void GetAdjusted() const
Definition: itrtxt.hxx:250
sal_uInt16 GetLineNr() const
Definition: itrtxt.hxx:87
bool IsClipping() const
Definition: porlay.hxx:138
bool ChkSpecialUnderline() const
Definition: redlnitr.hxx:119
bool InSpaceGrp() const
Definition: porlin.hxx:109
bool IsRest() const
Definition: porlay.hxx:119
sal_uInt16 Height() const
Definition: possiz.hxx:44
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:436
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
Extracts pool item of type nWhich from rAttr.
Definition: atrstck.cxx:157
void CtorInitTextPainter(SwTextFrame *pFrame, SwTextPaintInfo *pInf)
Definition: itrpaint.cxx:63
sal_uIntPtr sal_uLong
void SetFillColor(const Color &rColor)
Definition: swfont.hxx:433
const SwRect & getFramePrintArea() const
Definition: frame.hxx:178
void Height(long nNew)
Definition: swrect.hxx:191
short Seek(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew, sal_Int32 nOld)
Definition: redlnitr.cxx:535
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
SwFont * m_pFont
Definition: itratr.hxx:39
bool SeekAndChg(SwTextSizeInfo &rInf)
Definition: itrtxt.hxx:310
long SwTwips
Definition: swtypes.hxx:49
bool Select(sal_Int32 nIndex, bool bSelect=true)
const Size & GetSize(SwFontScript nWhich) const
Definition: swfont.hxx:204
void SetKanaComp(std::deque< sal_uInt16 > *pNew)
Definition: inftxt.hxx:329
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
bool InFieldGrp() const
Definition: porlin.hxx:104
SwTwips Y() const
Definition: itrtxt.hxx:90
sal_Int32 GetRangeCount() const
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
std::vector< long > * GetpLLSpaceAdd() const
Definition: porlay.hxx:179
void SetColor(const Color &rColor)
Definition: swfont.hxx:411
long GetLen(const Point &rPnt)
WEIGHT_BOLD
const SwFont * GetFont() const
Definition: atrhndl.hxx:114
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
void Top(const long nTop)
Definition: swrect.hxx:204
LINESTYLE_NONE
bool IsBreakPortion() const
Definition: porlin.hxx:114
const SwRect & getFrameArea() const
Definition: frame.hxx:177
size_t pos
#define X
bool IsInTab() const
Definition: frame.hxx:933
SwTwips Right() const
Definition: itrtxt.hxx:181
long GetSpaceAdd() const
Definition: inftxt.hxx:447
SwTextPaintInfo & GetInfo()
Definition: itrpaint.hxx:57
bool IsTextFrame() const
Definition: frame.hxx:1212
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 Right(const long nRight)
Definition: swrect.hxx:200
void ChgPhysFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.cxx:963
void SetStrikeout(const FontStrikeout eStrikeout)
Definition: swfont.hxx:572
SwFontScript GetActual() const
Definition: swfont.hxx:182
void SetPaintOfst(const SwTwips nNew)
Definition: inftxt.hxx:742
SwTwips Y() const
Definition: inftxt.hxx:387
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:245
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:231
void SetFont(SwFont *pNew)
Definition: inftxt.hxx:240
SwParaPortion * GetParaPortion()
Definition: inftxt.hxx:128
bool IsFlyPortion() const
Definition: porlin.hxx:125
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1170
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2539
SwLinePortion * GetFirstPortion() const
Definition: porlay.cxx:670
long GetHeight() const
Definition: swfont.hxx:280
bool IsParagraph(bool bHard=false) const
Definition: viewopt.hxx:231
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(MergedPara const &, TextFrameIndex nIndex)
Definition: txtfrm.cxx:1151
SwFont & GetFont()
Definition: swfont.hxx:962
TextFrameIndex GetEnd() const
Definition: swfont.hxx:968
WEIGHT_NORMAL
void ResetSpaceIdx()
Definition: inftxt.hxx:443
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:278
void SetWeight(const FontWeight eWeight, const SwFontScript nWhich)
Definition: swfont.hxx:529
bool IsPDFExport() const
Definition: viewopt.hxx:390
long GetTopMargin() const
Definition: ssfrm.cxx:39
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:291
Point GetTopLeft() const
Definition: itrtxt.hxx:186
const OUString & GetText() const
Definition: inftxt.hxx:246
const Range & GetRange(sal_Int32 nRange) const
bool IsHolePortion() const
Definition: porlin.hxx:126
long GetBottomMargin() const
Definition: ssfrm.cxx:41
SwUnderlineFont * GetUnderFnt() const
Definition: inftxt.hxx:243
const Point & GetPos() const
Definition: inftxt.hxx:435
bool IsMultiPortion() const
Definition: porlin.hxx:134
FontLineStyle GetUnderline() const
Definition: swfont.hxx:268
FontLineStyle GetLineStyle() const
SwTwips X() const
Definition: inftxt.hxx:385
SwTextFrame * m_pFrame
Definition: itrtxt.hxx:34
void CheckSpecialUnderline(const SwLinePortion *pPor, long nAdjustBaseLine=0)
Definition: itrpaint.cxx:480
Base class for anything that can be part of a line in the Writer layout.
Definition: porlin.hxx:50
long Max() const
void CtorInitTextCursor(SwTextFrame *pFrame, SwTextSizeInfo *pInf)
Definition: itrcrsr.cxx:392
void Left(const long nLeft)
Definition: swrect.hxx:195
bool SeekAndChgBefore(SwTextSizeInfo &rInf)
Definition: itrtxt.hxx:315
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
void Bottom(const long nBottom)
Definition: swrect.hxx:209
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:46
void SetLen(const TextFrameIndex nNew)
Definition: inftxt.hxx:281
void SetSize(const Size &rSize, const SwFontScript nWhich)
Definition: swfont.hxx:734
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:424
bool HasSpecialAlign(bool bVert) const
Definition: inftxt.hxx:93
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: porrst.cxx:56
bool OnWin() const
Definition: inftxt.hxx:199
bool InTextGrp() const
Definition: porlin.hxx:98
sal_uInt16 Width() const
Definition: possiz.hxx:46
SwScriptInfo & GetScriptInfo()
Definition: porlay.hxx:270
SwFontScript
Definition: swfont.hxx:122
double getLength(const B2DPolygon &rCandidate)
void DrawRedArrow(const SwLinePortion &rPor) const
Definition: inftxt.cxx:1017
bool IsChg() const
Definition: txtpaint.hxx:53
const SwLineLayout * GetCurr() const
Definition: itrtxt.hxx:83
bool HasRedline() const
Definition: porlay.hxx:125
bool IsArrowPortion() const
Definition: porlin.hxx:133
SwTextFrame * GetTextFrame()
Definition: itrtxt.hxx:134
void ResetKanaIdx()
Definition: inftxt.hxx:326
bool IsWordLineMode() const
Definition: swfont.hxx:274
SwLineLayout * m_pCurr
Definition: itrtxt.hxx:36
long Min() const
STRIKEOUT_NONE
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)
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:762
SwLinePortion * GetNextPortion() const
Definition: porlin.hxx:72
void SetIdx(const TextFrameIndex nNew)
Definition: inftxt.hxx:279
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
virtual long CalcSpacing(long nSpaceAdd, const SwTextSizeInfo &rInf) const
Definition: porlin.cxx:305
void SetOverline(const FontLineStyle eOverline)
Definition: swfont.hxx:557
bool IsFlyCntPortion() const
Definition: porlin.hxx:112
sal_uInt16 & GetAscent()
Definition: porlin.hxx:77
void SetpSpaceAdd(std::vector< long > *pNew)
Definition: inftxt.hxx:451
SwRedlineItr * GetRedln()
Definition: itratr.hxx:81
bool HasUnderscore() const
Definition: porlay.hxx:131
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:656