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