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