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 <swmodule.hxx>
28 #include <redline.hxx>
29 #include <txtatr.hxx>
30 #include <docary.hxx>
31 #include "itratr.hxx"
32 #include <ndtxt.hxx>
33 #include <doc.hxx>
36 #include <rootfrm.hxx>
37 #include <breakit.hxx>
38 #include <vcl/keycodes.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 #include <sfx2/printer.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, USHRT_MAX);
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 
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
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 = &rTextNode; // if every node is empty, the first 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  for (auto iter = ++nodes.begin(); iter != nodes.end(); ++iter)
280  {
281  (**iter).DelFrames(rFrame.getRootFrame());
282  }
283  // also delete tables & sections here; not necessary, but convenient
284  for (auto const pTableNode : tables)
285  {
286  pTableNode->DelFrames(rFrame.getRootFrame());
287  }
288  for (auto const pSectionNode : sections)
289  {
290  pSectionNode->DelFrames(rFrame.getRootFrame());
291  }
292  }
293  auto pRet(std::make_unique<sw::MergedPara>(rFrame, std::move(extents),
294  mergedText.makeStringAndClear(), pParaPropsNode, &rTextNode,
295  nodes.back()));
296  for (SwTextNode * pTmp : nodes)
297  {
298  pRet->listener.StartListening(pTmp);
299  }
300  rFrame.EndListeningAll();
301  return pRet;
302 }
303 
304 } // namespace sw
305 
307  SwTextNode const& rPropsNode,
308  SwTextNode const& rTextNode,
309  OUString const& rText,
310  bool const*const pbVertLayout,
311  bool const*const pbVertLayoutLRBT)
312 {
313  // Build a font matching the default paragraph style:
314  SwFontAccess aFontAccess( &rPropsNode.GetAnyFormatColl(), m_pViewShell );
315  // It is possible that Init is called more than once, e.g., in a
316  // SwTextFrame::FormatOnceMore situation or (since sw_redlinehide)
317  // from SwAttrIter::Seek(); in the latter case SwTextSizeInfo::m_pFnt
318  // is an alias of m_pFont so it must not be deleted!
319  if (m_pFont)
320  {
321  *m_pFont = aFontAccess.Get()->GetFont();
322  }
323  else
324  {
325  m_pFont = new SwFont( aFontAccess.Get()->GetFont() );
326  }
327 
328  // set font to vertical if frame layout is vertical
329  // if it's a re-init, the vert flag never changes
330  if (pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout())
331  {
332  bool bVertLayoutLRBT = false;
333  if (pbVertLayoutLRBT)
334  bVertLayoutLRBT = *pbVertLayoutLRBT;
335  m_pFont->SetVertical(m_pFont->GetOrientation(), true, bVertLayoutLRBT);
336  }
337 
338  // Initialize the default attribute of the attribute handler
339  // based on the attribute array cached together with the font.
340  // If any further attributes for the paragraph are given in pAttrSet
341  // consider them during construction of the default array, and apply
342  // them to the font
343  m_aAttrHandler.Init(aFontAccess.Get()->GetDefault(), rTextNode.GetpSwAttrSet(),
345  pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout() );
346 
348 
349  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
350 
351  m_pFont->SetActual( m_pScriptInfo->WhichFont(TextFrameIndex(0)) );
352 
353  TextFrameIndex nChg(0);
354  size_t nCnt = 0;
355 
356  do
357  {
358  if ( nCnt >= m_pScriptInfo->CountScriptChg() )
359  break;
360  nChg = m_pScriptInfo->GetScriptChg( nCnt );
361  SwFontScript nTmp = SW_SCRIPTS;
362  switch ( m_pScriptInfo->GetScriptType( nCnt++ ) ) {
363  case i18n::ScriptType::ASIAN :
365  break;
366  case i18n::ScriptType::COMPLEX :
368  break;
369  default:
371  }
372  if( nTmp < SW_SCRIPTS )
373  {
374  m_pFont->CheckFontCacheId( m_pViewShell, nTmp );
375  m_pFont->GetFontCacheId( m_aFontCacheIds[ nTmp ], m_aFontIdx[ nTmp ], nTmp );
376  }
377  }
378  while (nChg < TextFrameIndex(rText.getLength()));
379 }
380 
382  SwScriptInfo & rScriptInfo, SwTextFrame const*const pFrame)
383 {
384  // during HTML-Import it can happen, that no layout exists
385  SwRootFrame* pRootFrame = rTextNode.getIDocumentLayoutAccess().GetCurrentLayout();
386  m_pViewShell = pRootFrame ? pRootFrame->GetCurrShell() : nullptr;
387 
388  m_pScriptInfo = &rScriptInfo;
389 
390  // set font to vertical if frame layout is vertical
391  bool bVertLayout = false;
392  bool bVertLayoutLRBT = false;
393  bool bRTL = false;
394  if ( pFrame )
395  {
396  if ( pFrame->IsVertical() )
397  {
398  bVertLayout = true;
399  }
400  if (pFrame->IsVertLRBT())
401  {
402  bVertLayoutLRBT = true;
403  }
404  bRTL = pFrame->IsRightToLeft();
405  m_pMergedPara = pFrame->GetMergedPara();
406  }
407 
408  // determine script changes if not already done for current paragraph
409  assert(m_pScriptInfo);
411  m_pScriptInfo->InitScriptInfo(rTextNode, m_pMergedPara, bRTL);
412 
415  rTextNode,
416  m_pMergedPara ? m_pMergedPara->mergedText : rTextNode.GetText(),
417  & bVertLayout,
418  & bVertLayoutLRBT);
419 
421  m_nPropFont = 0;
422  SwDoc* pDoc = rTextNode.GetDoc();
423  const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
424 
425  // sw_redlinehide: this is a Ring - pExtInp is the first PaM that's inside
426  // the node. It's not clear whether there can be more than 1 PaM in the
427  // Ring, and this code doesn't handle that case; neither did the old code.
428  const SwExtTextInput* pExtInp = pDoc->GetExtTextInput( rTextNode );
429  if (!pExtInp && m_pMergedPara)
430  {
431  SwTextNode const* pNode(&rTextNode);
432  for (auto const& rExtent : m_pMergedPara->extents)
433  {
434  if (rExtent.pNode != pNode)
435  {
436  pNode = rExtent.pNode;
437  pExtInp = pDoc->GetExtTextInput(*pNode);
438  if (pExtInp)
439  break;
440  }
441  }
442  }
443  const bool bShow = IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
444  && pRootFrame && !pRootFrame->IsHideRedlines();
445  if (pExtInp || m_pMergedPara || bShow)
446  {
447  SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
448  if (SwRedlineTable::npos == nRedlPos && m_pMergedPara)
449  {
450  SwTextNode const* pNode(&rTextNode);
451  for (auto const& rExtent : m_pMergedPara->extents)
452  { // note: have to search because extents based only on Delete
453  if (rExtent.pNode != pNode)
454  {
455  pNode = rExtent.pNode;
456  nRedlPos = rIDRA.GetRedlinePos(*pNode, USHRT_MAX);
457  if (SwRedlineTable::npos != nRedlPos)
458  break;
459  }
460  }
461  // TODO this is true initially but after delete ops it may be false... need to delete m_pMerged somewhere?
462  // assert(SwRedlineTable::npos != nRedlPos);
463  assert(SwRedlineTable::npos != nRedlPos || m_pMergedPara->extents.size() <= 1);
464  }
465  if (pExtInp || m_pMergedPara || SwRedlineTable::npos != nRedlPos)
466  {
467  const std::vector<ExtTextInputAttr> *pArr = nullptr;
468  if( pExtInp )
469  {
470  pArr = &pExtInp->GetAttrs();
471  Seek( TextFrameIndex(0) );
472  }
473 
474  m_pRedline.reset(new SwRedlineItr( rTextNode, *m_pFont, m_aAttrHandler, nRedlPos,
477  : bShow
480  pArr, pExtInp ? pExtInp->Start() : nullptr));
481 
482  if( m_pRedline->IsOn() )
483  ++m_nChgCnt;
484  }
485  }
486 }
487 
488 // The Redline-Iterator
489 // The following information/states exist in RedlineIterator:
490 //
491 // m_nFirst is the first index of RedlineTable, which overlaps with the paragraph.
492 //
493 // m_nAct is the currently active (if m_bOn is set) or the next possible index.
494 // m_nStart and m_nEnd give you the borders of the object within the paragraph.
495 //
496 // If m_bOn is set, the font has been manipulated according to it.
497 //
498 // If m_nAct is set to SwRedlineTable::npos (via Reset()), then currently no
499 // Redline is active, m_nStart and m_nEnd are invalid.
501  SwAttrHandler& rAH, sal_Int32 nRed,
502  Mode const mode,
503  const std::vector<ExtTextInputAttr> *pArr,
504  SwPosition const*const pExtInputStart)
505  : m_rDoc( *rTextNd.GetDoc() )
506  , m_rAttrHandler( rAH )
507  , m_nNdIdx( rTextNd.GetIndex() )
508  , m_nFirst( nRed )
509  , m_nAct( SwRedlineTable::npos )
510  , m_bOn( false )
511  , m_eMode( mode )
512 {
513  if( pArr )
514  {
515  assert(pExtInputStart);
516  m_pExt.reset( new SwExtend(*pArr, pExtInputStart->nNode.GetIndex(),
517  pExtInputStart->nContent.GetIndex()) );
518  }
519  else
520  m_pExt = nullptr;
521  assert(m_pExt || m_eMode != Mode::Ignore); // only create if necessary
522  Seek(rFnt, m_nNdIdx, 0, COMPLETE_STRING);
523 }
524 
525 SwRedlineItr::~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
526 {
527  Clear( nullptr );
528  m_pExt.reset();
529 }
530 
531 // The return value of SwRedlineItr::Seek tells you if the current font
532 // has been manipulated by leaving (-1) or accessing (+1) of a section
534  sal_uLong const nNode, sal_Int32 const nNew, sal_Int32 const nOld)
535 {
536  short nRet = 0;
537  if( ExtOn() )
538  return 0; // Abbreviation: if we're within an ExtendTextInputs
539  // there can't be other changes of attributes (not even by redlining)
540  assert(m_eMode == Mode::Hide || m_nNdIdx == nNode);
541  if (m_eMode == Mode::Show)
542  {
543  if (m_bOn)
544  {
545  if (nNew >= m_nEnd)
546  {
547  --nRet;
548  Clear_( &rFnt ); // We go behind the current section
549  ++m_nAct; // and check the next one
550  }
551  else if (nNew < m_nStart)
552  {
553  --nRet;
554  Clear_( &rFnt ); // We go in front of the current section
555  if (m_nAct > m_nFirst)
556  m_nAct = m_nFirst; // the test has to run from the beginning
557  else
558  return nRet + EnterExtend(rFnt, nNode, nNew); // There's none prior to us
559  }
560  else
561  return nRet + EnterExtend(rFnt, nNode, nNew); // We stayed in the same section
562  }
563  if (SwRedlineTable::npos == m_nAct || nOld > nNew)
564  m_nAct = m_nFirst;
565 
568 
570  {
572 
573  if (nNew < m_nEnd)
574  {
575  if (nNew >= m_nStart) // only possible candidate
576  {
577  m_bOn = true;
579 
580  if (m_pSet)
581  m_pSet->ClearItem();
582  else
583  {
584  SwAttrPool& rPool =
585  const_cast<SwDoc&>(m_rDoc).GetAttrPool();
586  m_pSet = std::make_unique<SfxItemSet>(rPool, svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END-1>{});
587  }
588 
589  if( 1 < pRed->GetStackCount() )
590  FillHints( pRed->GetAuthor( 1 ), pRed->GetType( 1 ) );
591  FillHints( pRed->GetAuthor(), pRed->GetType() );
592 
593  SfxWhichIter aIter( *m_pSet );
594  sal_uInt16 nWhich = aIter.FirstWhich();
595  while( nWhich )
596  {
597  const SfxPoolItem* pItem;
598  if( ( nWhich < RES_CHRATR_END ) &&
599  ( SfxItemState::SET == m_pSet->GetItemState( nWhich, true, &pItem ) ) )
600  {
602  const_cast<SwDoc&>(m_rDoc),
603  *const_cast<SfxPoolItem*>(pItem) );
604  pAttr->SetPriorityAttr( true );
605  m_Hints.push_back(pAttr);
606  m_rAttrHandler.PushAndChg( *pAttr, rFnt );
607  }
608  nWhich = aIter.NextWhich();
609  }
610 
611  ++nRet;
612  }
613  break;
614  }
617  }
618  }
619  else if (m_eMode == Mode::Hide)
620  { // ... just iterate to update m_nAct for GetNextRedln();
621  // there is no need to care about formatting in this mode
622  if (m_nAct == SwRedlineTable::npos || nOld == COMPLETE_STRING)
623  { // reset, or move backward
624  m_nAct = m_nFirst;
625  }
627  { // only Start matters in this mode
628  // Seeks until it finds a RL that starts at or behind the seek pos.
629  // - then update m_nStart/m_nEnd to the intersection of it with the
630  // current node (if any).
631  // The only way to skip to a different node is if there is a Delete
632  // RL, so if there is no intersection we'll never skip again.
633  // Note: here, assume that delete can't nest inside delete!
634  SwRangeRedline const*const pRedline(
636  SwPosition const*const pStart(pRedline->Start());
637  if (pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE
638  && (nNode < pStart->nNode.GetIndex()
639  || (nNode == pStart->nNode.GetIndex()
640  && nNew <= pStart->nContent.GetIndex())))
641  {
642  pRedline->CalcStartEnd(nNode, m_nStart, m_nEnd);
643  break;
644  }
647  }
648  }
649  return nRet + EnterExtend(rFnt, nNode, nNew);
650 }
651 
652 void SwRedlineItr::FillHints( std::size_t nAuthor, RedlineType_t eType )
653 {
654  switch ( eType )
655  {
657  SW_MOD()->GetInsertAuthorAttr(nAuthor, *m_pSet);
658  break;
660  SW_MOD()->GetDeletedAuthorAttr(nAuthor, *m_pSet);
661  break;
664  SW_MOD()->GetFormatAuthorAttr(nAuthor, *m_pSet);
665  break;
666  default:
667  break;
668  }
669 }
670 
671 void SwRedlineItr::ChangeTextAttr( SwFont* pFnt, SwTextAttr const &rHt, bool bChg )
672 {
673  OSL_ENSURE( IsOn(), "SwRedlineItr::ChangeTextAttr: Off?" );
674 
675  if (m_eMode != Mode::Show && !m_pExt)
676  return;
677 
678  if( bChg )
679  {
680  if (m_pExt && m_pExt->IsOn())
681  m_rAttrHandler.PushAndChg( rHt, *m_pExt->GetFont() );
682  else
683  m_rAttrHandler.PushAndChg( rHt, *pFnt );
684  }
685  else
686  {
687  OSL_ENSURE( ! m_pExt || ! m_pExt->IsOn(), "Pop of attribute during opened extension" );
688  m_rAttrHandler.PopAndChg( rHt, *pFnt );
689  }
690 }
691 
693 {
694  OSL_ENSURE( m_bOn, "SwRedlineItr::Clear: Off?" );
695  m_bOn = false;
696  for (auto const& hint : m_Hints)
697  {
698  if( pFnt )
699  m_rAttrHandler.PopAndChg( *hint, *pFnt );
700  else
701  m_rAttrHandler.Pop( *hint );
702  SwTextAttr::Destroy(hint, const_cast<SwDoc&>(m_rDoc).GetAttrPool() );
703  }
704  m_Hints.clear();
705 }
706 
711 std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>>
712 SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode,
714 {
715  sal_Int32 nStart(m_nStart);
716  sal_Int32 nEnd(m_nEnd);
717  nNext = NextExtend(pNode->GetIndex(), nNext);
719  return std::make_pair(nNext, std::make_pair(nullptr, 0));
720  if (SwRedlineTable::npos == rAct)
721  {
722  rAct = m_nFirst;
723  }
724  if (rAct != m_nAct)
725  {
727  {
728  SwRangeRedline const*const pRedline(
730  pRedline->CalcStartEnd(pNode->GetIndex(), nStart, nEnd);
731  if (m_eMode != Mode::Hide
732  || pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE)
733  {
734  break;
735  }
736  ++rAct; // Hide mode: search a Delete RL
737  }
738  }
740  {
741  return std::make_pair(nNext, std::make_pair(nullptr, 0)); // no Delete here
742  }
743  if (m_bOn || (m_eMode == Mode::Show && nStart == 0))
744  { // in Ignore mode, the end of redlines isn't relevant, except as returned in the second in the pair!
745  if (nEnd < nNext)
746  nNext = nEnd;
747  }
748  else if (nStart <= nNext)
749  {
750  if (m_eMode == Mode::Show)
751  {
752  nNext = nStart;
753  }
754  else
755  {
756  assert(m_eMode == Mode::Hide);
757  SwRangeRedline const* pRedline(
759  assert(pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE); //?
760  if (pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE)
761  {
762  nNext = nStart;
763  size_t nSkipped(1); // (consecutive) candidates to be skipped
764  while (rAct + nSkipped <
766  {
767  SwRangeRedline const*const pNext =
768  m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct + nSkipped];
769  if (*pRedline->End() < *pNext->Start())
770  {
771  break; // done for now
772  }
773  else if (*pNext->Start() == *pRedline->End() &&
775  {
776  // consecutive delete - continue
777  pRedline = pNext;
778  }
779  ++nSkipped;
780  }
781  return std::make_pair(nNext, std::make_pair(pRedline, nSkipped));
782  }
783  }
784  }
785  return std::make_pair(nNext, std::make_pair(nullptr, 0));
786 }
787 
789 {
790  // If the underlining or the escapement is caused by redlining,
791  // we always apply the SpecialUnderlining, i.e. the underlining
792  // below the base line
793  for (SwTextAttr* pHint : m_Hints)
794  {
795  const sal_uInt16 nWhich = pHint->Which();
796  if( RES_CHRATR_UNDERLINE == nWhich ||
797  RES_CHRATR_ESCAPEMENT == nWhich )
798  return true;
799  }
800  return false;
801 }
802 
804  sal_uLong const nStartNode, sal_Int32 const nChkStart,
805  sal_uLong const nEndNode, sal_Int32 nChkEnd)
806 {
807  // note: previously this would return true in the (!m_bShow && m_pExt)
808  // case, but surely that was a bug?
810  return false;
811  assert(nStartNode == nEndNode); (void) nStartNode; (void) nEndNode;
812  if( nChkEnd == nChkStart ) // empty lines look one char further
813  ++nChkEnd;
814  sal_Int32 nOldStart = m_nStart;
815  sal_Int32 nOldEnd = m_nEnd;
816  SwRedlineTable::size_type const nOldAct = m_nAct;
817  bool bRet = false;
818 
820  {
822  if (nChkEnd < m_nStart)
823  break;
824  if (nChkStart <= m_nEnd && (nChkEnd > m_nStart || COMPLETE_STRING == m_nEnd))
825  {
826  bRet = true;
827  break;
828  }
829  }
830 
831  m_nStart = nOldStart;
832  m_nEnd = nOldEnd;
833  m_nAct = nOldAct;
834  return bRet;
835 }
836 
838 {
839  if ( nAttr & ExtTextInputAttr::Underline )
841  else if ( nAttr & ExtTextInputAttr::BoldUnderline )
843  else if ( nAttr & ExtTextInputAttr::DottedUnderline )
845  else if ( nAttr & ExtTextInputAttr::DashDotUnderline )
847 
848  if ( nAttr & ExtTextInputAttr::RedText )
849  rFnt.SetColor( COL_RED );
850 
851  if ( nAttr & ExtTextInputAttr::Highlight )
852  {
853  const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
854  rFnt.SetColor( rStyleSettings.GetHighlightTextColor() );
855  rFnt.SetBackColor( new Color( rStyleSettings.GetHighlightColor() ) );
856  }
857  if ( nAttr & ExtTextInputAttr::GrayWaveline )
858  rFnt.SetGreyWave( true );
859 }
860 
861 short SwExtend::Enter(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
862 {
863  OSL_ENSURE( !m_pFont, "SwExtend: Enter with Font" );
864  if (nNode != m_nNode)
865  return 0;
866  OSL_ENSURE( !Inside(), "SwExtend: Enter without Leave" );
867  m_nPos = nNew;
868  if( Inside() )
869  {
870  m_pFont.reset( new SwFont(rFnt) );
871  ActualizeFont( rFnt, m_rArr[m_nPos - m_nStart] );
872  return 1;
873  }
874  return 0;
875 }
876 
877 bool SwExtend::Leave_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
878 {
879  OSL_ENSURE(nNode == m_nNode && Inside(), "SwExtend: Leave without Enter");
880  if (nNode != m_nNode)
881  return true;
882  const ExtTextInputAttr nOldAttr = m_rArr[m_nPos - m_nStart];
883  m_nPos = nNew;
884  if( Inside() )
885  { // We stayed within the ExtendText-section
886  const ExtTextInputAttr nAttr = m_rArr[m_nPos - m_nStart];
887  if( nOldAttr != nAttr ) // Is there an (inner) change of attributes?
888  {
889  rFnt = *m_pFont;
890  ActualizeFont( rFnt, nAttr );
891  }
892  }
893  else
894  {
895  rFnt = *m_pFont;
896  m_pFont.reset();
897  return true;
898  }
899  return false;
900 }
901 
902 sal_Int32 SwExtend::Next(sal_uLong const nNode, sal_Int32 nNext)
903 {
904  if (nNode != m_nNode)
905  return nNext;
906  if (m_nPos < m_nStart)
907  {
908  if (nNext > m_nStart)
909  nNext = m_nStart;
910  }
911  else if (m_nPos < m_nEnd)
912  {
913  sal_Int32 nIdx = m_nPos - m_nStart;
914  const ExtTextInputAttr nAttr = m_rArr[ nIdx ];
915  while (static_cast<size_t>(++nIdx) < m_rArr.size() && nAttr == m_rArr[nIdx])
916  ; //nothing
917  nIdx = nIdx + m_nStart;
918  if( nNext > nIdx )
919  nNext = nIdx;
920  }
921  return nNext;
922 }
923 
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 m_nEnd
Definition: redlnitr.hxx:84
SwScriptInfo * m_pScriptInfo
Definition: itratr.hxx:46
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
std::deque< SwTextAttr * > m_Hints
Definition: redlnitr.hxx:74
SwFontScript WhichFont(TextFrameIndex nIdx) const
Definition: porlay.cxx:723
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
const RedlineType_t REDLINE_FORMAT
void Pop(const SwTextAttr &rAttr)
Only used during redlining.
Definition: atrstck.cxx:537
const SwNodeNum * GetNum(SwRootFrame const *pLayout=nullptr) const
Definition: ndtxt.cxx:3967
const OUString & GetText() const
Definition: ndtxt.hxx:211
virtual const SwRootFrame * GetCurrentLayout() const =0
void PopAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:496
std::unique_ptr< SwFont > m_pFont
Definition: redlnitr.hxx:41
const Color & GetHighlightTextColor() const
SwNodeIndex nNode
Definition: pam.hxx:37
constexpr::Color COL_RED(0x80, 0x00, 0x00)
void SetPriorityAttr(bool bFlag)
Definition: txatbase.hxx:93
LINESTYLE_BOLD
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
sal_uIntPtr sal_uLong
#define SW_SCRIPTS
Definition: swfont.hxx:125
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
size_t m_nEndIndex
current iteration index in HintEnds
Definition: itratr.hxx:56
sw::MergedPara * GetMergedPara()
Definition: txtfrm.hxx:438
void SetGreyWave(const bool bNew)
Definition: swfont.hxx:820
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:533
sal_Int32 const m_nStart
Definition: redlnitr.hxx:45
SwFont * m_pFont
Definition: itratr.hxx:45
Dialog to specify the properties of drop-down form field.
Definition: accframe.hxx:34
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:1316
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:411
size_type size() const
Definition: docary.hxx:370
sal_Int32 m_nStart
Definition: redlnitr.hxx:83
sal_Int32 m_nPosition
current iteration index in text node
Definition: itratr.hxx:58
#define RES_CHRATR_END
Definition: hintids.hxx:114
void CtorInitAttrIter(SwTextNode &rTextNode, SwScriptInfo &rScrInf, SwTextFrame const *pFrame=nullptr)
Definition: redlnitr.cxx:381
SwIndex nContent
Definition: pam.hxx:38
o3tl::enumarray< SwFontScript, sal_uInt16 > m_aFontIdx
Definition: itratr.hxx:61
SwRedlineTable::size_type m_nAct
Definition: redlnitr.hxx:82
bool ExtOn()
Definition: redlnitr.hxx:125
bool Leave_(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew)
Definition: redlnitr.cxx:877
std::unique_ptr< sw::MergedPara > CheckParaRedlineMerge(SwTextFrame &rFrame, SwTextNode &rTextNode, FrameMode eMode)
Definition: redlnitr.cxx:53
bool IsOn() const
Definition: redlnitr.hxx:110
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:34
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
void InitScriptInfo(const SwTextNode &rNode, sw::MergedPara const *pMerged, bool bRTL)
Definition: porlay.cxx:742
void SetUnderline(const FontLineStyle eUnderline)
Definition: swfont.hxx:542
sal_Int32 Next(sal_uLong nNode, sal_Int32 nNext)
Definition: redlnitr.cxx:902
const RedlineType_t REDLINE_DELETE
std::unique_ptr< SwRedlineItr, o3tl::default_delete< SwRedlineItr > > m_pRedline
Definition: itratr.hxx:52
sal_uInt16 GetStackCount() const
Definition: docredln.cxx:1756
sal_Int32 m_nPos
current position (inside)
Definition: redlnitr.hxx:47
SwFormatColl & GetAnyFormatColl() const
Definition: node.hxx:716
void EndListeningAll()
Definition: calbck.cxx:124
FrameMode
Definition: txtfrm.hxx:103
std::vector< Extent > extents
Definition: txtfrm.hxx:955
void InitFontAndAttrHandler(SwTextNode const &rPropsNode, SwTextNode const &rTextNode, OUString const &rText, bool const *pbVertLayout, bool const *pbVertLayoutLRBT)
Definition: redlnitr.cxx:306
bool Inside() const
Definition: redlnitr.hxx:51
std::unique_ptr< SfxItemSet > m_pSet
Definition: redlnitr.hxx:77
sw::MergedPara const * m_pMergedPara
Definition: itratr.hxx:64
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, sal_uInt16 nType) const =0
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:443
RedlineType_t GetType(sal_uInt16 nPos=0) const
Definition: redline.hxx:225
#define SW_MOD()
Definition: swmodule.hxx:255
void Init(const SwAttrSet &rAttrSet, const IDocumentSettingAccess &rIDocumentSettingAccess)
Definition: atrstck.cxx:357
const IDocumentRedlineAccess & getIDocumentRedlineAccess() const
Provides access to the document redline interface.
Definition: node.cxx:2041
sal_uLong const m_nNdIdx
Definition: redlnitr.hxx:80
bool IsVertLayout() const
Definition: atrhndl.hxx:118
int i
vector_type::size_type size_type
Definition: docary.hxx:331
std::unique_ptr< SwExtend > m_pExt
Definition: redlnitr.hxx:78
const RedlineType_t REDLINE_FMTCOLL
LINESTYLE_SINGLE
sal_Int32 const m_nEnd
position of end of SwExtTextInput (in same node as start)
Definition: redlnitr.hxx:49
#define RES_CHRATR_BEGIN
Definition: hintids.hxx:68
SwTextNode * pParaPropsNode
most paragraph properties are taken from the first non-empty node
Definition: txtfrm.hxx:960
#define RES_CHRATR_UNDERLINE
Definition: hintids.hxx:82
~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
Definition: redlnitr.cxx:525
void RemoveFootnotesForNode(SwRootFrame const &rLayout, SwTextNode const &rTextNode, std::vector< std::pair< sal_Int32, sal_Int32 >> const *const pExtents)
Definition: txtfrm.cxx:800
#define RES_CHRATR_ESCAPEMENT
Definition: hintids.hxx:74
const IDocumentSettingAccess * getIDocumentSettingAccess() const
Provides access to the document setting interface.
Definition: node.cxx:2039
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:44
OUString mergedText
note: cannot be const currently to avoid UB because SwTextGuess::Guess const_casts it and modifies it...
Definition: txtfrm.hxx:958
const SwPosition * Start() const
Definition: pam.hxx:212
size_t m_nStartIndex
current iteration index in HintStarts
Definition: itratr.hxx:54
sal_uInt8 m_nPropFont
Definition: itratr.hxx:59
const IDocumentLayoutAccess & getIDocumentLayoutAccess() const
Provides access to the document layout interface.
Definition: node.cxx:2044
const SwDoc & m_rDoc
Definition: redlnitr.hxx:75
const RedlineType_t REDLINE_INSERT
SwRedlineTable::size_type const m_nFirst
Definition: redlnitr.hxx:81
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
void FillHints(std::size_t nAuthor, RedlineType_t eType)
Definition: redlnitr.cxx:652
Mode const m_eMode
Definition: redlnitr.hxx:89
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:367
void Clear_(SwFont *pFnt)
Definition: redlnitr.cxx:692
o3tl::enumarray< SwFontScript, const void * > m_aFontCacheIds
Definition: itratr.hxx:60
sal_uInt16 RedlineType_t
std::size_t GetAuthor(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1764
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:712
LINESTYLE_DOTTED
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:259
static bool IsHideChanges(const RedlineFlags eM)
bool CheckLine(sal_uLong nStartNode, sal_Int32 nChkStart, sal_uLong nEndNode, sal_Int32 nChkEnd)
Definition: redlnitr.cxx:803
SwAttrHandler m_aAttrHandler
Definition: itratr.hxx:43
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:54
bool ChkSpecialUnderline_() const
Definition: redlnitr.cxx:788
SwFontScript
Definition: swfont.hxx:119
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:671
void PushAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:423
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter()
Definition: breakit.hxx:62
const std::vector< ExtTextInputAttr > & m_rArr
Definition: redlnitr.hxx:42
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:500
ExtTextInputAttr
bool IsInList() const
Definition: ndtxt.cxx:4344
short Enter(SwFont &rFnt, sal_uLong nNode, sal_Int32 nNew)
Definition: redlnitr.cxx:861
SwAttrHandler & m_rAttrHandler
Definition: redlnitr.hxx:76
SwViewShell * m_pViewShell
Definition: itratr.hxx:44
virtual const SwRedlineTable & GetRedlineTable() const =0
short m_nChgCnt
count currently open hints, redlines, ext-input
Definition: itratr.hxx:51
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:94
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:332
static void ActualizeFont(SwFont &rFnt, ExtTextInputAttr nAttr)
Definition: redlnitr.cxx:837
Merge GetRedlineMergeFlag() const
Definition: node.hxx:97
void Clear(SwFont *pFnt)
Definition: redlnitr.hxx:111
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:266
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:99
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:949