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