LibreOffice Module sw (master)  1
redlnitr.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 <sal/config.h>
21 
22 #include <string_view>
23 
24 #include <hintids.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <svl/whiter.hxx>
27 #include <com/sun/star/i18n/ScriptType.hpp>
28 #include <scriptinfo.hxx>
29 #include <swmodule.hxx>
30 #include <redline.hxx>
31 #include <txatbase.hxx>
32 #include <docary.hxx>
33 #include "itratr.hxx"
34 #include <ndtxt.hxx>
35 #include <doc.hxx>
38 #include <rootfrm.hxx>
39 #include <breakit.hxx>
40 #include <vcl/commandevent.hxx>
41 #include <vcl/settings.hxx>
42 #include <txtfrm.hxx>
43 #include <ftnfrm.hxx>
44 #include <vcl/svapp.hxx>
45 #include "redlnitr.hxx"
46 #include <extinput.hxx>
47 
48 using namespace ::com::sun::star;
49 
50 namespace sw {
51 
52 std::unique_ptr<sw::MergedPara>
54  FrameMode const eMode)
55 {
56  IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess();
57  if (!rFrame.getRootFrame()->IsHideRedlines())
58  {
59  return nullptr;
60  }
61  bool bHaveRedlines(false);
62  std::vector<SwTextNode *> nodes{ &rTextNode };
63  std::vector<SwTableNode *> tables;
64  std::vector<SwSectionNode *> sections;
65  std::vector<sw::Extent> extents;
66  OUStringBuffer mergedText;
67  SwTextNode * pParaPropsNode(nullptr);
68  SwTextNode * pNode(&rTextNode);
69  sal_Int32 nLastEnd(0);
70  for (auto i = rIDRA.GetRedlinePos(rTextNode, RedlineType::Any);
71  i < rIDRA.GetRedlineTable().size(); ++i)
72  {
73  SwRangeRedline const*const pRed = rIDRA.GetRedlineTable()[i];
74 
75  if (pNode->GetIndex() < pRed->Start()->nNode.GetIndex())
76  break;
77 
78  if (pRed->GetType() != RedlineType::Delete)
79  continue;
80 
81  SwPosition const*const pStart(pRed->Start());
82  SwPosition const*const pEnd(pRed->End());
83  if (*pStart == *pEnd)
84  { // only allowed while moving (either way?)
85 // assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags()));
86  continue;
87  }
88  if (pStart->nNode.GetNode().IsTableNode())
89  {
90  assert(&pEnd->nNode.GetNode() == &rTextNode && pEnd->nContent.GetIndex() == 0);
91  continue; // known pathology, ignore it
92  }
93  bHaveRedlines = true;
94  assert(pNode != &rTextNode || &pStart->nNode.GetNode() == &rTextNode); // detect calls with wrong start node
95  if (pStart->nContent != nLastEnd) // not 0 so we eliminate adjacent deletes
96  {
97  extents.emplace_back(pNode, nLastEnd, pStart->nContent.GetIndex());
98  mergedText.append(std::u16string_view(pNode->GetText()).substr(nLastEnd, pStart->nContent.GetIndex() - nLastEnd));
99  }
100  if (&pEnd->nNode.GetNode() != pNode)
101  {
102  if (pNode == &rTextNode)
103  {
105  } // else: was already set before
106  int nLevel(0);
107  for (sal_uLong j = pNode->GetIndex() + 1; j < pEnd->nNode.GetIndex(); ++j)
108  {
109  SwNode *const pTmp(pNode->GetNodes()[j]);
110  if (nLevel == 0)
111  {
112  if (pTmp->IsTextNode())
113  {
114  nodes.push_back(pTmp->GetTextNode());
115  }
116  else if (pTmp->IsTableNode())
117  {
118  tables.push_back(pTmp->GetTableNode());
119  }
120  else if (pTmp->IsSectionNode())
121  {
122  sections.push_back(pTmp->GetSectionNode());
123  }
124  }
125  if (pTmp->IsStartNode())
126  {
127  ++nLevel;
128  }
129  else if (pTmp->IsEndNode())
130  {
131  --nLevel;
132  }
134  }
135  // note: in DelLastPara() case, the end node is not actually merged
136  // and is likely a SwTableNode!
137  if (!pEnd->nNode.GetNode().IsTextNode())
138  {
139  assert(pEnd->nNode != pStart->nNode);
140  // must set pNode too because it will mark the last node
141  pNode = nodes.back();
142  assert(pNode == pNode->GetNodes()[pEnd->nNode.GetIndex() - 1]);
143  if (pNode != &rTextNode)
144  { // something might depend on last merged one being NonFirst?
146  }
147  nLastEnd = pNode->Len();
148  }
149  else
150  {
151  pNode = pEnd->nNode.GetNode().GetTextNode();
152  nodes.push_back(pNode);
154  nLastEnd = pEnd->nContent.GetIndex();
155  }
156  }
157  else
158  {
159  nLastEnd = pEnd->nContent.GetIndex();
160  }
161  }
162  if (pNode == &rTextNode)
163  {
164  if (rTextNode.GetRedlineMergeFlag() != SwNode::Merge::None)
165  {
167  }
168  }
169  // Reset flag of the following text node since we know it's not merged;
170  // also any table/sections in between.
171  // * the following SwTextNode is in same nodes section as pNode (nLevel=0)
172  // * the start nodes that don't have a SwTextNode before them
173  // on their level, and their corresponding end nodes
174  // * the first SwTextNode inside each start node of the previous point
175  // Other (non-first) SwTextNodes in nested sections shouldn't be reset!
176  int nLevel(0);
177  for (sal_uLong j = pNode->GetIndex() + 1; j < pNode->GetNodes().Count(); ++j)
178  {
179  SwNode *const pTmp(pNode->GetNodes()[j]);
180  if (!pTmp->IsCreateFrameWhenHidingRedlines())
181  { // clear stale flag caused by editing with redlines shown
183  }
184  if (pTmp->IsStartNode())
185  {
186  ++nLevel;
187  }
188  else if (pTmp->IsEndNode())
189  {
190  if (nLevel == 0)
191  {
192  break; // there is no following text node; avoid leaving section
193  }
194  --nLevel;
195  }
196  else if (pTmp->IsTextNode())
197  {
198  if (nLevel == 0)
199  {
200  break; // done
201  }
202  else
203  { // skip everything other than 1st text node in section!
204  j = pTmp->EndOfSectionIndex() - 1; // will be incremented again
205  }
206  }
207  }
208  if (!bHaveRedlines)
209  {
210  if (rTextNode.IsInList() && !rTextNode.GetNum(rFrame.getRootFrame()))
211  {
212  rTextNode.AddToListRLHidden(); // try to add it...
213  }
214  return nullptr;
215  }
216  if (nLastEnd != pNode->Len())
217  {
218  extents.emplace_back(pNode, nLastEnd, pNode->Len());
219  mergedText.append(std::u16string_view(pNode->GetText()).substr(nLastEnd, pNode->Len() - nLastEnd));
220  }
221  if (extents.empty()) // there was no text anywhere
222  {
223  assert(mergedText.isEmpty());
224  pParaPropsNode = pNode; // if every node is empty, the last one wins
225  }
226  else
227  {
228  assert(!mergedText.isEmpty());
229  pParaPropsNode = extents.begin()->pNode; // para props from first node that isn't empty
230  }
231 // pParaPropsNode = &rTextNode; // well, actually...
232  // keep lists up to date with visible nodes
233  if (pParaPropsNode->IsInList() && !pParaPropsNode->GetNum(rFrame.getRootFrame()))
234  {
235  pParaPropsNode->AddToListRLHidden(); // try to add it...
236  }
237  for (auto const pTextNode : nodes)
238  {
239  if (pTextNode != pParaPropsNode)
240  {
241  pTextNode->RemoveFromListRLHidden();
242  }
243  }
244  if (eMode == FrameMode::Existing)
245  {
246  // remove existing footnote frames for first node;
247  // for non-first nodes with own frames, DelFrames will remove all
248  // (could possibly call lcl_ChangeFootnoteRef, not sure if worth it)
249  // note: must be done *before* changing listeners!
250  // for non-first nodes that are already merged with this frame,
251  // need to remove here too, otherwise footnotes can be removed only
252  // by lucky accident, e.g. TruncLines().
253  auto itExtent(extents.begin());
254  for (auto const pTextNode : nodes)
255  {
256  sal_Int32 nLast(0);
257  std::vector<std::pair<sal_Int32, sal_Int32>> hidden;
258  for ( ; itExtent != extents.end(); ++itExtent)
259  {
260  if (itExtent->pNode != pTextNode)
261  {
262  break;
263  }
264  if (itExtent->nStart != 0)
265  {
266  assert(itExtent->nStart != nLast);
267  hidden.emplace_back(nLast, itExtent->nStart);
268  }
269  nLast = itExtent->nEnd;
270  }
271  if (nLast != pTextNode->Len())
272  {
273  hidden.emplace_back(nLast, pTextNode->Len());
274  }
275  sw::RemoveFootnotesForNode(*rFrame.getRootFrame(), *pTextNode, &hidden);
276  }
277  // unfortunately DelFrames() must be done before StartListening too,
278  // otherwise footnotes cannot be deleted by SwTextFootnote::DelFrames!
279  auto const end(--nodes.rend());
280  for (auto iter = nodes.rbegin(); iter != end; ++iter)
281  {
282  (**iter).DelFrames(rFrame.getRootFrame());
283  }
284  // also delete tables & sections here; not necessary, but convenient
285  for (auto const pTableNode : tables)
286  {
287  pTableNode->DelFrames(rFrame.getRootFrame());
288  }
289  for (auto const pSectionNode : sections)
290  {
291  pSectionNode->DelFrames(rFrame.getRootFrame());
292  }
293  }
294  auto pRet(std::make_unique<sw::MergedPara>(rFrame, std::move(extents),
295  mergedText.makeStringAndClear(), pParaPropsNode, &rTextNode,
296  nodes.back()));
297  for (SwTextNode * pTmp : nodes)
298  {
299  pRet->listener.StartListening(pTmp);
300  }
301  rFrame.EndListeningAll();
302  return pRet;
303 }
304 
305 } // namespace sw
306 
308  SwTextNode const& rPropsNode,
309  SwTextNode const& rTextNode,
310  OUString const& rText,
311  bool const*const pbVertLayout,
312  bool const*const pbVertLayoutLRBT)
313 {
314  // Build a font matching the default paragraph style:
315  SwFontAccess aFontAccess( &rPropsNode.GetAnyFormatColl(), m_pViewShell );
316  // It is possible that Init is called more than once, e.g., in a
317  // SwTextFrame::FormatOnceMore situation or (since sw_redlinehide)
318  // from SwAttrIter::Seek(); in the latter case SwTextSizeInfo::m_pFnt
319  // is an alias of m_pFont so it must not be deleted!
320  if (m_pFont)
321  {
322  *m_pFont = aFontAccess.Get()->GetFont();
323  }
324  else
325  {
326  m_pFont = new SwFont( aFontAccess.Get()->GetFont() );
327  }
328 
329  // set font to vertical if frame layout is vertical
330  // if it's a re-init, the vert flag never changes
331  bool bVertLayoutLRBT = false;
332  if (pbVertLayoutLRBT)
333  bVertLayoutLRBT = *pbVertLayoutLRBT;
334  if (pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout())
335  {
336  m_pFont->SetVertical(m_pFont->GetOrientation(), true, bVertLayoutLRBT);
337  }
338 
339  // Initialize the default attribute of the attribute handler
340  // based on the attribute array cached together with the font.
341  // If any further attributes for the paragraph are given in pAttrSet
342  // consider them during construction of the default array, and apply
343  // them to the font
344  m_aAttrHandler.Init(aFontAccess.Get()->GetDefault(), rTextNode.GetpSwAttrSet(),
346  pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout(),
347  bVertLayoutLRBT );
348 
350 
352 
353  m_pFont->SetActual( m_pScriptInfo->WhichFont(TextFrameIndex(0)) );
354 
355  TextFrameIndex nChg(0);
356  size_t nCnt = 0;
357 
358  do
359  {
360  if ( nCnt >= m_pScriptInfo->CountScriptChg() )
361  break;
362  nChg = m_pScriptInfo->GetScriptChg( nCnt );
363  SwFontScript nTmp = SW_SCRIPTS;
364  switch ( m_pScriptInfo->GetScriptType( nCnt++ ) ) {
365  case i18n::ScriptType::ASIAN :
367  break;
368  case i18n::ScriptType::COMPLEX :
370  break;
371  default:
373  }
374  if( nTmp < SW_SCRIPTS )
375  {
376  m_pFont->CheckFontCacheId( m_pViewShell, nTmp );
377  m_pFont->GetFontCacheId( m_aFontCacheIds[ nTmp ], m_aFontIdx[ nTmp ], nTmp );
378  }
379  }
380  while (nChg < TextFrameIndex(rText.getLength()));
381 }
382 
384  SwScriptInfo & rScriptInfo, SwTextFrame const*const pFrame)
385 {
386  // during HTML-Import it can happen, that no layout exists
387  SwRootFrame* pRootFrame = rTextNode.getIDocumentLayoutAccess().GetCurrentLayout();
388  m_pViewShell = pRootFrame ? pRootFrame->GetCurrShell() : nullptr;
389 
390  m_pScriptInfo = &rScriptInfo;
391 
392  // set font to vertical if frame layout is vertical
393  bool bVertLayout = false;
394  bool bVertLayoutLRBT = false;
395  bool bRTL = false;
396  if ( pFrame )
397  {
398  if ( pFrame->IsVertical() )
399  {
400  bVertLayout = true;
401  }
402  if (pFrame->IsVertLRBT())
403  {
404  bVertLayoutLRBT = true;
405  }
406  bRTL = pFrame->IsRightToLeft();
407  m_pMergedPara = pFrame->GetMergedPara();
408  }
409 
410  // determine script changes if not already done for current paragraph
413  m_pScriptInfo->InitScriptInfo(rTextNode, m_pMergedPara, bRTL);
414 
417  rTextNode,
418  m_pMergedPara ? m_pMergedPara->mergedText : rTextNode.GetText(),
419  & bVertLayout,
420  & bVertLayoutLRBT);
421 
423  m_nPropFont = 0;
424  SwDoc* pDoc = rTextNode.GetDoc();
425  const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
426 
427  // sw_redlinehide: this is a Ring - pExtInp is the first PaM that's inside
428  // the node. It's not clear whether there can be more than 1 PaM in the
429  // Ring, and this code doesn't handle that case; neither did the old code.
430  const SwExtTextInput* pExtInp = pDoc->GetExtTextInput( rTextNode );
431  if (!pExtInp && m_pMergedPara)
432  {
433  SwTextNode const* pNode(&rTextNode);
434  for (auto const& rExtent : m_pMergedPara->extents)
435  {
436  if (rExtent.pNode != pNode)
437  {
438  pNode = rExtent.pNode;
439  pExtInp = pDoc->GetExtTextInput(*pNode);
440  if (pExtInp)
441  break;
442  }
443  }
444  }
445  const bool bShow = IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
446  && pRootFrame && !pRootFrame->IsHideRedlines();
447  if (!(pExtInp || m_pMergedPara || bShow))
448  return;
449 
450  SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, RedlineType::Any );
451  if (SwRedlineTable::npos == nRedlPos && m_pMergedPara)
452  {
453  SwTextNode const* pNode(&rTextNode);
454  for (auto const& rExtent : m_pMergedPara->extents)
455  { // note: have to search because extents based only on Delete
456  if (rExtent.pNode != pNode)
457  {
458  pNode = rExtent.pNode;
459  nRedlPos = rIDRA.GetRedlinePos(*pNode, RedlineType::Any);
460  if (SwRedlineTable::npos != nRedlPos)
461  break;
462  }
463  }
464  // TODO this is true initially but after delete ops it may be false... need to delete m_pMerged somewhere?
465  // assert(SwRedlineTable::npos != nRedlPos);
466  assert(SwRedlineTable::npos != nRedlPos || m_pMergedPara->extents.size() <= 1);
467  }
468  if (!(pExtInp || m_pMergedPara || SwRedlineTable::npos != nRedlPos))
469  return;
470 
471  const std::vector<ExtTextInputAttr> *pArr = nullptr;
472  if( pExtInp )
473  {
474  pArr = &pExtInp->GetAttrs();
475  Seek( TextFrameIndex(0) );
476  }
477 
478  m_pRedline.reset(new SwRedlineItr( rTextNode, *m_pFont, m_aAttrHandler, nRedlPos,
481  : bShow
484  pArr, pExtInp ? pExtInp->Start() : nullptr));
485 
486  if( m_pRedline->IsOn() )
487  ++m_nChgCnt;
488 }
489 
490 // The Redline-Iterator
491 // The following information/states exist in RedlineIterator:
492 //
493 // m_nFirst is the first index of RedlineTable, which overlaps with the paragraph.
494 //
495 // m_nAct is the currently active (if m_bOn is set) or the next possible index.
496 // m_nStart and m_nEnd give you the borders of the object within the paragraph.
497 //
498 // If m_bOn is set, the font has been manipulated according to it.
499 //
500 // If m_nAct is set to SwRedlineTable::npos (via Reset()), then currently no
501 // Redline is active, m_nStart and m_nEnd are invalid.
503  SwAttrHandler& rAH, sal_Int32 nRed,
504  Mode const mode,
505  const std::vector<ExtTextInputAttr> *pArr,
506  SwPosition const*const pExtInputStart)
507  : m_rDoc( *rTextNd.GetDoc() )
508  , m_rAttrHandler( rAH )
509  , m_nNdIdx( rTextNd.GetIndex() )
510  , m_nFirst( nRed )
511  , m_nAct( SwRedlineTable::npos )
512  , m_bOn( false )
513  , m_eMode( mode )
514 {
515  if( pArr )
516  {
517  assert(pExtInputStart);
518  m_pExt.reset( new SwExtend(*pArr, pExtInputStart->nNode.GetIndex(),
519  pExtInputStart->nContent.GetIndex()) );
520  }
521  else
522  m_pExt = nullptr;
523  assert(m_pExt || m_eMode != Mode::Ignore); // only create if necessary
524  Seek(rFnt, m_nNdIdx, 0, COMPLETE_STRING);
525 }
526 
527 SwRedlineItr::~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
528 {
529  Clear( nullptr );
530  m_pExt.reset();
531 }
532 
533 // The return value of SwRedlineItr::Seek tells you if the current font
534 // has been manipulated by leaving (-1) or accessing (+1) of a section
536  sal_uLong const nNode, sal_Int32 const nNew, sal_Int32 const nOld)
537 {
538  short nRet = 0;
539  if( ExtOn() )
540  return 0; // Abbreviation: if we're within an ExtendTextInputs
541  // there can't be other changes of attributes (not even by redlining)
542  assert(m_eMode == Mode::Hide || m_nNdIdx == nNode);
543  if (m_eMode == Mode::Show)
544  {
545  if (m_bOn)
546  {
547  if (nNew >= m_nEnd)
548  {
549  --nRet;
550  Clear_( &rFnt ); // We go behind the current section
551  ++m_nAct; // and check the next one
552  }
553  else if (nNew < m_nStart)
554  {
555  --nRet;
556  Clear_( &rFnt ); // We go in front of the current section
557  if (m_nAct > m_nFirst)
558  m_nAct = m_nFirst; // the test has to run from the beginning
559  else
560  return nRet + EnterExtend(rFnt, nNode, nNew); // There's none prior to us
561  }
562  else
563  return nRet + EnterExtend(rFnt, nNode, nNew); // We stayed in the same section
564  }
565  if (SwRedlineTable::npos == m_nAct || nOld > nNew)
566  m_nAct = m_nFirst;
567 
570 
572  {
574 
575  if (nNew < m_nEnd)
576  {
577  if (nNew >= m_nStart) // only possible candidate
578  {
579  m_bOn = true;
581 
582  if (m_pSet)
583  m_pSet->ClearItem();
584  else
585  {
586  SwAttrPool& rPool =
587  const_cast<SwDoc&>(m_rDoc).GetAttrPool();
588  m_pSet = std::make_unique<SfxItemSet>(rPool, svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END-1>{});
589  }
590 
591  if( 1 < pRed->GetStackCount() )
592  FillHints( pRed->GetAuthor( 1 ), pRed->GetType( 1 ) );
593  FillHints( pRed->GetAuthor(), pRed->GetType() );
594 
595  SfxWhichIter aIter( *m_pSet );
596  sal_uInt16 nWhich = aIter.FirstWhich();
597  while( nWhich )
598  {
599  const SfxPoolItem* pItem;
600  if( ( nWhich < RES_CHRATR_END ) &&
601  ( SfxItemState::SET == m_pSet->GetItemState( nWhich, true, &pItem ) ) )
602  {
604  const_cast<SwDoc&>(m_rDoc),
605  *const_cast<SfxPoolItem*>(pItem) );
606  pAttr->SetPriorityAttr( true );
607  m_Hints.push_back(pAttr);
608  m_rAttrHandler.PushAndChg( *pAttr, rFnt );
609  }
610  nWhich = aIter.NextWhich();
611  }
612 
613  ++nRet;
614  }
615  break;
616  }
619  }
620  }
621  else if (m_eMode == Mode::Hide)
622  { // ... just iterate to update m_nAct for GetNextRedln();
623  // there is no need to care about formatting in this mode
624  if (m_nAct == SwRedlineTable::npos || nOld == COMPLETE_STRING)
625  { // reset, or move backward
626  m_nAct = m_nFirst;
627  }
629  { // only Start matters in this mode
630  // Seeks until it finds a RL that starts at or behind the seek pos.
631  // - then update m_nStart/m_nEnd to the intersection of it with the
632  // current node (if any).
633  // The only way to skip to a different node is if there is a Delete
634  // RL, so if there is no intersection we'll never skip again.
635  // Note: here, assume that delete can't nest inside delete!
636  SwRangeRedline const*const pRedline(
638  SwPosition const*const pStart(pRedline->Start());
639  if (pRedline->GetType() == RedlineType::Delete
640  && (nNode < pStart->nNode.GetIndex()
641  || (nNode == pStart->nNode.GetIndex()
642  && nNew <= pStart->nContent.GetIndex())))
643  {
644  pRedline->CalcStartEnd(nNode, m_nStart, m_nEnd);
645  break;
646  }
649  }
650  }
651  return nRet + EnterExtend(rFnt, nNode, nNew);
652 }
653 
654 void SwRedlineItr::FillHints( std::size_t nAuthor, RedlineType eType )
655 {
656  switch ( eType )
657  {
658  case RedlineType::Insert:
659  SW_MOD()->GetInsertAuthorAttr(nAuthor, *m_pSet);
660  break;
661  case RedlineType::Delete:
662  SW_MOD()->GetDeletedAuthorAttr(nAuthor, *m_pSet);
663  break;
664  case RedlineType::Format:
665  case RedlineType::FmtColl:
666  SW_MOD()->GetFormatAuthorAttr(nAuthor, *m_pSet);
667  break;
668  default:
669  break;
670  }
671 }
672 
673 void SwRedlineItr::ChangeTextAttr( SwFont* pFnt, SwTextAttr const &rHt, bool bChg )
674 {
675  OSL_ENSURE( IsOn(), "SwRedlineItr::ChangeTextAttr: Off?" );
676 
677  if (m_eMode != Mode::Show && !m_pExt)
678  return;
679 
680  if( bChg )
681  {
682  if (m_pExt && m_pExt->IsOn())
683  m_rAttrHandler.PushAndChg( rHt, *m_pExt->GetFont() );
684  else
685  m_rAttrHandler.PushAndChg( rHt, *pFnt );
686  }
687  else
688  {
689  OSL_ENSURE( ! m_pExt || ! m_pExt->IsOn(), "Pop of attribute during opened extension" );
690  m_rAttrHandler.PopAndChg( rHt, *pFnt );
691  }
692 }
693 
695 {
696  OSL_ENSURE( m_bOn, "SwRedlineItr::Clear: Off?" );
697  m_bOn = false;
698  for (auto const& hint : m_Hints)
699  {
700  if( pFnt )
701  m_rAttrHandler.PopAndChg( *hint, *pFnt );
702  else
703  m_rAttrHandler.Pop( *hint );
704  SwTextAttr::Destroy(hint, const_cast<SwDoc&>(m_rDoc).GetAttrPool() );
705  }
706  m_Hints.clear();
707 }
708 
713 std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>>
714 SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode,
716 {
717  sal_Int32 nStart(m_nStart);
718  sal_Int32 nEnd(m_nEnd);
719  nNext = NextExtend(pNode->GetIndex(), nNext);
721  return std::make_pair(nNext, std::make_pair(nullptr, 0));
722  if (SwRedlineTable::npos == rAct)
723  {
724  rAct = m_nFirst;
725  }
726  if (rAct != m_nAct)
727  {
729  {
730  SwRangeRedline const*const pRedline(
732  pRedline->CalcStartEnd(pNode->GetIndex(), nStart, nEnd);
733  if (m_eMode != Mode::Hide
734  || pRedline->GetType() == RedlineType::Delete)
735  {
736  break;
737  }
738  ++rAct; // Hide mode: search a Delete RL
739  }
740  }
742  {
743  return std::make_pair(nNext, std::make_pair(nullptr, 0)); // no Delete here
744  }
745  if (m_bOn || (m_eMode == Mode::Show && nStart == 0))
746  { // in Ignore mode, the end of redlines isn't relevant, except as returned in the second in the pair!
747  if (nEnd < nNext)
748  nNext = nEnd;
749  }
750  else if (nStart <= nNext)
751  {
752  if (m_eMode == Mode::Show)
753  {
754  nNext = nStart;
755  }
756  else
757  {
759  SwRangeRedline const* pRedline(
761  assert(pRedline->GetType() == RedlineType::Delete); //?
762  if (pRedline->GetType() == RedlineType::Delete)
763  {
764  nNext = nStart;
765  size_t nSkipped(1); // (consecutive) candidates to be skipped
766  while (rAct + nSkipped <
768  {
769  SwRangeRedline const*const pNext =
770  m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct + nSkipped];
771  if (*pRedline->End() < *pNext->Start())
772  {
773  break; // done for now
774  }
775  else if (*pNext->Start() == *pRedline->End() &&
776  pNext->GetType() == RedlineType::Delete)
777  {
778  // consecutive delete - continue
779  pRedline = pNext;
780  }
781  ++nSkipped;
782  }
783  return std::make_pair(nNext, std::make_pair(pRedline, nSkipped));
784  }
785  }
786  }
787  return std::make_pair(nNext, std::make_pair(nullptr, 0));
788 }
789 
791 {
792  // If the underlining or the escapement is caused by redlining,
793  // we always apply the SpecialUnderlining, i.e. the underlining
794  // below the base line
795  for (SwTextAttr* pHint : m_Hints)
796  {
797  const sal_uInt16 nWhich = pHint->Which();
798  if( RES_CHRATR_UNDERLINE == nWhich ||
799  RES_CHRATR_ESCAPEMENT == nWhich )
800  return true;
801  }
802  return false;
803 }
804 
806  sal_uLong const nStartNode, sal_Int32 const nChkStart,
807  sal_uLong const nEndNode, sal_Int32 nChkEnd)
808 {
809  // note: previously this would return true in the (!m_bShow && m_pExt)
810  // case, but surely that was a bug?
812  return false;
813  assert(nStartNode == nEndNode); (void) nStartNode; (void) nEndNode;
814  if( nChkEnd == nChkStart ) // empty lines look one char further
815  ++nChkEnd;
816  sal_Int32 nOldStart = m_nStart;
817  sal_Int32 nOldEnd = m_nEnd;
818  SwRedlineTable::size_type const nOldAct = m_nAct;
819  bool bRet = false;
820 
822  {
824  if (nChkEnd < m_nStart)
825  break;
826  if (nChkStart <= m_nEnd && (nChkEnd > m_nStart || COMPLETE_STRING == m_nEnd))
827  {
828  bRet = true;
829  break;
830  }
831  }
832 
833  m_nStart = nOldStart;
834  m_nEnd = nOldEnd;
835  m_nAct = nOldAct;
836  return bRet;
837 }
838 
840 {
841  if ( nAttr & ExtTextInputAttr::Underline )
843  else if ( nAttr & ExtTextInputAttr::BoldUnderline )
845  else if ( nAttr & ExtTextInputAttr::DottedUnderline )
847  else if ( nAttr & ExtTextInputAttr::DashDotUnderline )
849 
850  if ( nAttr & ExtTextInputAttr::RedText )
851  rFnt.SetColor( COL_RED );
852 
853  if ( nAttr & ExtTextInputAttr::Highlight )
854  {
855  const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
856  rFnt.SetColor( rStyleSettings.GetHighlightTextColor() );
857  rFnt.SetBackColor( new Color( rStyleSettings.GetHighlightColor() ) );
858  }
859  if ( nAttr & ExtTextInputAttr::GrayWaveline )
860  rFnt.SetGreyWave( true );
861 }
862 
863 short SwExtend::Enter(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
864 {
865  OSL_ENSURE( !m_pFont, "SwExtend: Enter with Font" );
866  if (nNode != m_nNode)
867  return 0;
868  OSL_ENSURE( !Inside(), "SwExtend: Enter without Leave" );
869  m_nPos = nNew;
870  if( Inside() )
871  {
872  m_pFont.reset( new SwFont(rFnt) );
873  ActualizeFont( rFnt, m_rArr[m_nPos - m_nStart] );
874  return 1;
875  }
876  return 0;
877 }
878 
879 bool SwExtend::Leave_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
880 {
881  OSL_ENSURE(nNode == m_nNode && Inside(), "SwExtend: Leave without Enter");
882  if (nNode != m_nNode)
883  return true;
884  const ExtTextInputAttr nOldAttr = m_rArr[m_nPos - m_nStart];
885  m_nPos = nNew;
886  if( Inside() )
887  { // We stayed within the ExtendText-section
888  const ExtTextInputAttr nAttr = m_rArr[m_nPos - m_nStart];
889  if( nOldAttr != nAttr ) // Is there an (inner) change of attributes?
890  {
891  rFnt = *m_pFont;
892  ActualizeFont( rFnt, nAttr );
893  }
894  }
895  else
896  {
897  rFnt = *m_pFont;
898  m_pFont.reset();
899  return true;
900  }
901  return false;
902 }
903 
904 sal_Int32 SwExtend::Next(sal_uLong const nNode, sal_Int32 nNext)
905 {
906  if (nNode != m_nNode)
907  return nNext;
908  if (m_nPos < m_nStart)
909  {
910  if (nNext > m_nStart)
911  nNext = m_nStart;
912  }
913  else if (m_nPos < m_nEnd)
914  {
915  sal_Int32 nIdx = m_nPos - m_nStart;
916  const ExtTextInputAttr nAttr = m_rArr[ nIdx ];
917  while (o3tl::make_unsigned(++nIdx) < m_rArr.size() && nAttr == m_rArr[nIdx])
918  ; //nothing
919  nIdx = nIdx + m_nStart;
920  if( nNext > nIdx )
921  nNext = nIdx;
922  }
923  return nNext;
924 }
925 
926 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 m_nEnd
Definition: redlnitr.hxx:83
SwScriptInfo * m_pScriptInfo
Definition: itratr.hxx:40
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:151
std::deque< SwTextAttr * > m_Hints
Definition: redlnitr.hxx:73
SwFontScript WhichFont(TextFrameIndex nIdx) const
Definition: porlay.cxx:721
sal_uLong GetIndex() const
Definition: node.hxx:282
TextFrameIndex GetInvalidityA() const
Definition: scriptinfo.hxx:117
sal_uLong Count() const
Definition: ndarr.hxx:142
Marks a position in the document model.
Definition: pam.hxx:35
constexpr TypedWhichId< SvxEscapementItem > RES_CHRATR_ESCAPEMENT(6)
void Pop(const SwTextAttr &rAttr)
Only used during redlining.
Definition: atrstck.cxx:467
const SwNodeNum * GetNum(SwRootFrame const *pLayout=nullptr) const
Definition: ndtxt.cxx:3960
const OUString & GetText() const
Definition: ndtxt.hxx:211
virtual const SwRootFrame * GetCurrentLayout() const =0
void PopAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:427
std::unique_ptr< SwFont > m_pFont
Definition: redlnitr.hxx:40
const Color & GetHighlightTextColor() const
SwNodeIndex nNode
Definition: pam.hxx:37
constexpr::Color COL_RED(0x80, 0x00, 0x00)
void SetPriorityAttr(bool bFlag)
Definition: txatbase.hxx:98
LINESTYLE_BOLD
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:275
sal_uIntPtr sal_uLong
#define SW_SCRIPTS
Definition: swfont.hxx:128
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
size_t m_nEndIndex
current iteration index in HintEnds
Definition: itratr.hxx:50
sw::MergedPara * GetMergedPara()
Definition: txtfrm.hxx:441
void SetGreyWave(const bool bNew)
Definition: swfont.hxx:815
Definition: doc.hxx:184
void SetBackColor(Color *pNewColor)
Definition: swfont.cxx:65
short Seek(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew, sal_Int32 nOld)
Definition: redlnitr.cxx:535
sal_Int32 const m_nStart
Definition: redlnitr.hxx:44
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
SwFont * m_pFont
Definition: itratr.hxx:39
Dialog to specify the properties of date form field.
sal_uInt16 GetOrientation(const bool bVertLayout=false, const bool bVertFormatLRBT=false) const
Definition: swfont.cxx:433
void CalcStartEnd(sal_uLong nNdIdx, sal_Int32 &rStart, sal_Int32 &rEnd) const
Calculates the intersection with text node number nNdIdx.
Definition: docredln.cxx:1270
The root element of a Writer document layout.
Definition: rootfrm.hxx:79
bool Seek(TextFrameIndex nPos)
Enables the attributes used at char pos nPos in the logical font.
Definition: itratr.cxx:301
const Color & GetHighlightColor() const
static bool IsShowChanges(const RedlineFlags eM)
bool IsVertLRBT() const
Definition: frame.hxx:961
void SetColor(const Color &rColor)
Definition: swfont.hxx:411
size_type size() const
Definition: docary.hxx:266
sal_Int32 m_nStart
Definition: redlnitr.hxx:82
sal_Int32 m_nPosition
current iteration index in text node
Definition: itratr.hxx:52
void CtorInitAttrIter(SwTextNode &rTextNode, SwScriptInfo &rScrInf, SwTextFrame const *pFrame=nullptr)
Definition: redlnitr.cxx:383
SwIndex nContent
Definition: pam.hxx:38
o3tl::enumarray< SwFontScript, sal_uInt16 > m_aFontIdx
Definition: itratr.hxx:55
SwRedlineTable::size_type m_nAct
Definition: redlnitr.hxx:81
void FillHints(std::size_t nAuthor, RedlineType eType)
Definition: redlnitr.cxx:654
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
bool ExtOn()
Definition: redlnitr.hxx:124
bool Leave_(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew)
Definition: redlnitr.cxx:879
std::unique_ptr< sw::MergedPara > CheckParaRedlineMerge(SwTextFrame &rFrame, SwTextNode &rTextNode, FrameMode eMode)
Definition: redlnitr.cxx:53
bool IsOn() const
Definition: redlnitr.hxx:109
Used by Attribute Iterators to organize attributes on stacks to find the valid attribute in each cate...
Definition: atrhndl.hxx:40
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:33
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
void InitScriptInfo(const SwTextNode &rNode, sw::MergedPara const *pMerged, bool bRTL)
Definition: porlay.cxx:907
void SetUnderline(const FontLineStyle eUnderline)
Definition: swfont.hxx:542
sal_Int32 Next(sal_uLong nNode, sal_Int32 nNext)
Definition: redlnitr.cxx:904
std::unique_ptr< SwRedlineItr, o3tl::default_delete< SwRedlineItr > > m_pRedline
Definition: itratr.hxx:46
sal_uInt16 GetStackCount() const
Definition: docredln.cxx:1711
sal_Int32 m_nPos
current position (inside)
Definition: redlnitr.hxx:46
SwFormatColl & GetAnyFormatColl() const
Definition: node.hxx:716
void EndListeningAll()
Definition: calbck.cxx:124
FrameMode
Definition: txtfrm.hxx:102
std::vector< Extent > extents
Definition: txtfrm.hxx:950
void InitFontAndAttrHandler(SwTextNode const &rPropsNode, SwTextNode const &rTextNode, OUString const &rText, bool const *pbVertLayout, bool const *pbVertLayoutLRBT)
Definition: redlnitr.cxx:307
bool Inside() const
Definition: redlnitr.hxx:50
std::unique_ptr< SfxItemSet > m_pSet
Definition: redlnitr.hxx:76
sw::MergedPara const * m_pMergedPara
Definition: itratr.hxx:58
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:443
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
#define SW_MOD()
Definition: swmodule.hxx:255
void Init(const SwAttrSet &rAttrSet, const IDocumentSettingAccess &rIDocumentSettingAccess)
Definition: atrstck.cxx:278
const IDocumentRedlineAccess & getIDocumentRedlineAccess() const
Provides access to the document redline interface.
Definition: node.cxx:2110
int i
sal_uLong const m_nNdIdx
Definition: redlnitr.hxx:79
bool IsVertLayout() const
Definition: atrhndl.hxx:82
vector_type::size_type size_type
Definition: docary.hxx:228
std::unique_ptr< SwExtend > m_pExt
Definition: redlnitr.hxx:77
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
LINESTYLE_SINGLE
sal_Int32 const m_nEnd
position of end of SwExtTextInput (in same node as start)
Definition: redlnitr.hxx:48
SwTextNode * pParaPropsNode
most paragraph properties are taken from the first non-empty node
Definition: txtfrm.hxx:955
~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
Definition: redlnitr.cxx:527
void RemoveFootnotesForNode(SwRootFrame const &rLayout, SwTextNode const &rTextNode, std::vector< std::pair< sal_Int32, sal_Int32 >> const *const pExtents)
Definition: txtfrm.cxx:802
const IDocumentSettingAccess * getIDocumentSettingAccess() const
Provides access to the document setting interface.
Definition: node.cxx:2108
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:693
sal_uLong const m_nNode
position of start of SwExtTextInput
Definition: redlnitr.hxx:43
OUString mergedText
note: cannot be const currently to avoid UB because SwTextGuess::Guess const_casts it and modifies it...
Definition: txtfrm.hxx:953
PDFDocument & m_rDoc
enumrange< T >::Iterator end(enumrange< T >)
const SwPosition * Start() const
Definition: pam.hxx:212
size_t m_nStartIndex
current iteration index in HintStarts
Definition: itratr.hxx:48
sal_uInt8 m_nPropFont
Definition: itratr.hxx:53
const IDocumentLayoutAccess & getIDocumentLayoutAccess() const
Provides access to the document layout interface.
Definition: node.cxx:2113
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:62
const SwDoc & m_rDoc
Definition: redlnitr.hxx:74
SwRedlineTable::size_type const m_nFirst
Definition: redlnitr.hxx:80
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
Mode const m_eMode
Definition: redlnitr.hxx:88
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:334
void Clear_(SwFont *pFnt)
Definition: redlnitr.cxx:694
o3tl::enumarray< SwFontScript, const void * > m_aFontCacheIds
Definition: itratr.hxx:54
constexpr sal_uInt16 RES_CHRATR_BEGIN(HINT_BEGIN)
std::size_t GetAuthor(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1719
std::pair< sal_Int32, std::pair< SwRangeRedline const *, size_t > > GetNextRedln(sal_Int32 nNext, SwTextNode const *pNode, SwRedlineTable::size_type &rAct)
Ignore mode: does nothing.
Definition: redlnitr.cxx:714
LINESTYLE_DOTTED
bool CheckLine(sal_uLong nStartNode, sal_Int32 nChkStart, sal_uLong nEndNode, sal_Int32 nChkEnd)
Definition: redlnitr.cxx:805
SwAttrHandler m_aAttrHandler
Definition: itratr.hxx:37
sal_uInt8 GetScriptType(const size_t nCnt) const
Definition: scriptinfo.hxx:132
sal_Int32 GetIndex() const
Definition: index.hxx:91
const SwPosition * End() const
Definition: pam.hxx:217
bool IsRightToLeft() const
Definition: frame.hxx:965
static void Destroy(SwTextAttr *pToDestroy, SfxItemPool &rPool)
destroy instance
Definition: txatbase.cxx:58
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1734
bool ChkSpecialUnderline_() const
Definition: redlnitr.cxx:790
SwFontScript
Definition: swfont.hxx:122
bool IsHideRedlines() const
Replacement for sw::DocumentRedlineManager::GetRedlineFlags() (this is layout-level redline hiding)...
Definition: rootfrm.hxx:416
constexpr sal_uInt16 RES_CHRATR_END(46)
void ChangeTextAttr(SwFont *pFnt, SwTextAttr const &rHt, bool bChg)
Definition: redlnitr.cxx:673
void PushAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:342
const std::vector< ExtTextInputAttr > & m_rArr
Definition: redlnitr.hxx:41
bool IsVertical() const
Definition: frame.hxx:951
TextFrameIndex GetScriptChg(const size_t nCnt) const
Definition: scriptinfo.hxx:127
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
size_t CountScriptChg() const
Definition: scriptinfo.hxx:126
void AddToListRLHidden()
Definition: ndtxt.cxx:4313
SwRedlineItr(const SwTextNode &rTextNd, SwFont &rFnt, SwAttrHandler &rAH, sal_Int32 nRedlPos, Mode mode, const std::vector< ExtTextInputAttr > *pArr=nullptr, SwPosition const *pExtInputStart=nullptr)
Definition: redlnitr.cxx:502
ExtTextInputAttr
bool IsInList() const
Definition: ndtxt.cxx:4356
RedlineType
short Enter(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew)
Definition: redlnitr.cxx:863
SwAttrHandler & m_rAttrHandler
Definition: redlnitr.hxx:75
SwViewShell * m_pViewShell
Definition: itratr.hxx:38
virtual const SwRedlineTable & GetRedlineTable() const =0
short m_nChgCnt
count currently open hints, redlines, ext-input
Definition: itratr.hxx:45
void SetVertical(sal_uInt16 nDir, const bool bVertLayout=false, const bool bVertLayoutLRBT=false)
Definition: swfont.cxx:438
short EnterExtend(SwFont &rFnt, sal_uLong const nNode, sal_Int32 const nNew)
Definition: redlnitr.hxx:93
void SetRedlineMergeFlag(Merge const eMerge)
Definition: node.hxx:96
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:204
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...
static constexpr size_type npos
Definition: docary.hxx:229
static void ActualizeFont(SwFont &rFnt, ExtTextInputAttr nAttr)
Definition: redlnitr.cxx:839
Merge GetRedlineMergeFlag() const
Definition: node.hxx:97
void Clear(SwFont *pFnt)
Definition: redlnitr.hxx:110
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
SwRootFrame * getRootFrame()
Definition: frame.hxx:659
SwExtTextInput * GetExtTextInput(const SwNode &rNd, sal_Int32 nContentPos=-1) const
Definition: extinput.cxx:263
const std::vector< ExtTextInputAttr > & GetAttrs() const
Definition: extinput.hxx:39
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:844
Base class of the Writer document model elements.
Definition: node.hxx:79
sal_Int32 NextExtend(sal_uLong const nNode, sal_Int32 const nNext)
Definition: redlnitr.hxx:98
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo
SwTextAttr * MakeRedlineTextAttr(SwDoc &rDoc, SfxPoolItem const &rAttr)
create redline dummy text hint that must not be inserted into hints array
Definition: thints.cxx:985