LibreOffice Module sw (master)  1
itratr.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 <algorithm>
23 
24 #include <hintids.hxx>
26 #include <txtatr.hxx>
27 #include <svl/itemiter.hxx>
28 #include <sfx2/printer.hxx>
29 #include <svx/svdobj.hxx>
30 #include <vcl/svapp.hxx>
31 #include <fmtanchr.hxx>
32 #include <fmtfsize.hxx>
33 #include <fmtornt.hxx>
34 #include <fmtflcnt.hxx>
35 #include <fmtcntnt.hxx>
36 #include <fmtftn.hxx>
37 #include <frmatr.hxx>
38 #include <frmfmt.hxx>
39 #include <fmtfld.hxx>
40 #include <doc.hxx>
44 #include <viewsh.hxx>
45 #include <rootfrm.hxx>
46 #include <docary.hxx>
47 #include <ndtxt.hxx>
48 #include <dcontact.hxx>
49 #include <fldbas.hxx>
50 #include <pam.hxx>
51 #include "itratr.hxx"
52 #include <htmltbl.hxx>
53 #include <swtable.hxx>
54 #include "redlnitr.hxx"
55 #include <redline.hxx>
56 #include <fmtsrnd.hxx>
57 #include "itrtxt.hxx"
58 #include <breakit.hxx>
59 #include <com/sun/star/i18n/WordType.hpp>
60 #include <com/sun/star/i18n/XBreakIterator.hpp>
61 #include <editeng/lrspitem.hxx>
62 #include <editeng/rsiditem.hxx>
63 #include <calbck.hxx>
64 
65 using namespace ::com::sun::star::i18n;
66 using namespace ::com::sun::star;
67 
68 static sal_Int32 GetNextAttrImpl(SwTextNode const* pTextNode,
69  size_t nStartIndex, size_t nEndIndex, sal_Int32 nPosition);
70 
72  : m_pViewShell(nullptr)
73  , m_pFont(nullptr)
74  , m_pScriptInfo(nullptr)
75  , m_pLastOut(nullptr)
76  , m_nChgCnt(0)
77  , m_nStartIndex(0)
78  , m_nEndIndex(0)
79  , m_nPosition(0)
80  , m_nPropFont(0)
81  , m_pTextNode(pTextNode)
82  , m_pMergedPara(nullptr)
83 {
85 }
86 
87 SwAttrIter::SwAttrIter(SwTextNode& rTextNode, SwScriptInfo& rScrInf, SwTextFrame const*const pFrame)
88  : m_pViewShell(nullptr)
89  , m_pFont(nullptr)
90  , m_pScriptInfo(nullptr)
91  , m_pLastOut(nullptr)
92  , m_nChgCnt(0)
93  , m_nPropFont(0)
94  , m_pTextNode(&rTextNode)
95  , m_pMergedPara(nullptr)
96 {
97  CtorInitAttrIter(rTextNode, rScrInf, pFrame);
98 }
99 
100 void SwAttrIter::Chg( SwTextAttr const *pHt )
101 {
102  assert(pHt && m_pFont && "No attribute of font available for change");
103  if( m_pRedline && m_pRedline->IsOn() )
104  m_pRedline->ChangeTextAttr( m_pFont, *pHt, true );
105  else
107  m_nChgCnt++;
108 }
109 
110 void SwAttrIter::Rst( SwTextAttr const *pHt )
111 {
112  assert(pHt && m_pFont && "No attribute of font available for reset");
113  // get top from stack after removing pHt
114  if( m_pRedline && m_pRedline->IsOn() )
115  m_pRedline->ChangeTextAttr( m_pFont, *pHt, false );
116  else
117  m_aAttrHandler.PopAndChg( *pHt, *m_pFont );
118  m_nChgCnt--;
119 }
120 
122 {
123  m_pRedline.reset();
124  delete m_pFont;
125 }
126 
128 {
129  return nullptr != m_pTextNode->GetpSwpHints() || nullptr != m_pMergedPara;
130 }
131 
148 {
149  std::pair<SwTextNode const*, sal_Int32> const pos( m_pMergedPara
150  ? sw::MapViewToModel(*m_pMergedPara, nPosition)
151  : std::make_pair(m_pTextNode, sal_Int32(nPosition)));
152  return pos.first->GetTextAttrForCharAt(pos.second);
153 }
154 
156 {
157  std::pair<SwTextNode const*, sal_Int32> const pos( m_pMergedPara
158  ? sw::MapViewToModel(*m_pMergedPara, nNewPos)
159  : std::make_pair(m_pTextNode, sal_Int32(nNewPos)));
160  bool bChg = m_nStartIndex && pos.first == m_pTextNode && pos.second == m_nPosition
161  ? m_pFont->IsFntChg()
162  : Seek( nNewPos );
163  if ( m_pLastOut.get() != pOut )
164  {
165  m_pLastOut = pOut;
166  m_pFont->SetFntChg( true );
167  bChg = true;
168  }
169  if( bChg )
170  {
171  // if the change counter is zero, we know the cache id of the wanted font
172  if ( !m_nChgCnt && !m_nPropFont )
175  m_pFont->ChgPhysFnt( m_pViewShell, *pOut );
176  }
177 
178  return bChg;
179 }
180 
182 {
183  Seek( nNewPos );
184  if ( !m_nChgCnt && !m_nPropFont )
187  return m_pFont->IsSymbol( m_pViewShell );
188 }
189 
191 {
192  SwTextInfo info(const_cast<SwTextFrame*>(this));
193  SwTextIter iter(const_cast<SwTextFrame*>(this), &info);
194  return iter.IsSymbol(nPos);
195 }
196 
197 bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFont )
198 {
199  SwTextNode const*const pFirstTextNode(m_pMergedPara ? m_pMergedPara->pFirstNode : m_pTextNode);
200  if ( m_pRedline && m_pRedline->ExtOn() )
201  m_pRedline->LeaveExtend(*m_pFont, pFirstTextNode->GetIndex(), 0);
202 
203  if (m_pTextNode != pFirstTextNode)
204  {
205  assert(m_pMergedPara);
206  m_pTextNode = m_pMergedPara->pFirstNode;
208  m_pMergedPara->mergedText, nullptr, nullptr);
209  }
210 
211  // reset font to its original state
214 
215  m_nStartIndex = 0;
216  m_nEndIndex = 0;
217  m_nPosition = 0;
218  m_nChgCnt = 0;
219  if( m_nPropFont )
221  if( m_pRedline )
222  {
223  m_pRedline->Clear( m_pFont );
224  if( !bParaFont )
225  m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, pFirstTextNode->GetIndex(), 0, COMPLETE_STRING);
226  else
227  m_pRedline->Reset();
228  }
229 
230  SwpHints const*const pHints(m_pTextNode->GetpSwpHints());
231  if (pHints && !bParaFont)
232  {
233  SwTextAttr *pTextAttr;
234  // While we've not reached the end of the StartArray && the TextAttribute starts at position 0...
235  while ((m_nStartIndex < pHints->Count()) &&
236  !((pTextAttr = pHints->Get(m_nStartIndex))->GetStart()))
237  {
238  // open the TextAttributes
239  Chg( pTextAttr );
240  m_nStartIndex++;
241  }
242  }
243 
244  bool bChg = m_pFont->IsFntChg();
245  if ( m_pLastOut.get() != pOut )
246  {
247  m_pLastOut = pOut;
248  m_pFont->SetFntChg( true );
249  bChg = true;
250  }
251  if( bChg )
252  {
253  // if the application counter is zero, we know the cache id of the wanted font
254  if ( !m_nChgCnt && !m_nPropFont )
257  m_pFont->ChgPhysFnt( m_pViewShell, *pOut );
258  }
259  return bChg;
260 }
261 
262 // AMA: New AttrIter Nov 94
263 void SwAttrIter::SeekFwd(const sal_Int32 nOldPos, const sal_Int32 nNewPos)
264 {
265  SwpHints const*const pHints(m_pTextNode->GetpSwpHints());
266  SwTextAttr *pTextAttr;
267 
268  if ( m_nStartIndex ) // If attributes have been opened at all ...
269  {
270  // Close attributes that are currently open, but stop at nNewPos+1
271 
272  // As long as we've not yet reached the end of EndArray and the
273  // TextAttribute ends before or at the new position ...
274  while ((m_nEndIndex < pHints->Count()) &&
275  ((pTextAttr = pHints->GetSortedByEnd(m_nEndIndex))->GetAnyEnd() <= nNewPos))
276  {
277  // Close the TextAttributes, whose StartPos were before or at
278  // the old nPos and are currently open
279  if (pTextAttr->GetStart() <= nOldPos) Rst( pTextAttr );
280  m_nEndIndex++;
281  }
282  }
283  else // skip the not opened ends
284  {
285  while ((m_nEndIndex < pHints->Count()) &&
286  (pHints->GetSortedByEnd(m_nEndIndex)->GetAnyEnd() <= nNewPos))
287  {
288  m_nEndIndex++;
289  }
290  }
291 
292  // As long as we've not yet reached the end of EndArray and the
293  // TextAttribute ends before or at the new position...
294  while ((m_nStartIndex < pHints->Count()) &&
295  ((pTextAttr = pHints->Get(m_nStartIndex))->GetStart() <= nNewPos))
296  {
297 
298  // open the TextAttributes, whose ends lie behind the new position
299  if ( pTextAttr->GetAnyEnd() > nNewPos ) Chg( pTextAttr );
300  m_nStartIndex++;
301  }
302 
303 }
304 
305 bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
306 {
307  // note: nNewPos isn't necessarily an index returned from GetNextAttr
308  std::pair<SwTextNode const*, sal_Int32> const newPos( m_pMergedPara
309  ? sw::MapViewToModel(*m_pMergedPara, nNewPos)
310  : std::make_pair(m_pTextNode, sal_Int32(nNewPos)));
311 
312  if ( m_pRedline && m_pRedline->ExtOn() )
313  m_pRedline->LeaveExtend(*m_pFont, newPos.first->GetIndex(), newPos.second);
314  if (m_pTextNode->GetIndex() < newPos.first->GetIndex())
315  {
316  // Skipping to a different node - first seek until the end of this node
317  // to get rid of all hint items
318  if (m_pTextNode->GetpSwpHints())
319  {
320  sal_Int32 nPos(m_nPosition);
321  do
322  {
323  sal_Int32 const nOldPos(nPos);
325  if (nPos <= m_pTextNode->Len())
326  {
327  SeekFwd(nOldPos, nPos);
328  }
329  else
330  {
331  SeekFwd(nOldPos, m_pTextNode->Len());
332  }
333  }
334  while (nPos < m_pTextNode->Len());
335  }
336  assert(m_nChgCnt == 0); // should have reset it all? there cannot be ExtOn() inside of a Delete redline, surely?
337  // Unapply current para items:
338  // the SwAttrHandler doesn't appear to be capable of *unapplying*
339  // items at all; it can only apply a previously effective item.
340  // So do this by recreating the font from scratch.
341  // Apply new para items:
342  assert(m_pMergedPara);
344  m_pMergedPara->mergedText, nullptr, nullptr);
345  // reset to next
346  m_pTextNode = newPos.first;
347  m_nStartIndex = 0;
348  m_nEndIndex = 0;
349  m_nPosition = 0;
350  assert(m_pRedline);
351  }
352 
353  // sw_redlinehide: Seek(0) must move before the first character, which
354  // has a special case where the first node starts with delete redline.
355  if ((!nNewPos && !m_pMergedPara)
356  || newPos.first != m_pTextNode
357  || newPos.second < m_nPosition)
358  {
359  if (m_pMergedPara)
360  {
361  if (m_pTextNode != newPos.first)
362  {
363  m_pTextNode = newPos.first;
364  // sw_redlinehide: hope it's okay to use the current text node
365  // here; the AttrHandler shouldn't care about non-char items
367  m_pMergedPara->mergedText, nullptr, nullptr);
368  }
369  }
371  {
372  if( m_pRedline )
373  m_pRedline->Clear( nullptr );
374 
375  // reset font to its original state
378 
379  if( m_nPropFont )
381  m_nStartIndex = 0;
382  m_nEndIndex = 0;
383  m_nPosition = 0;
384  m_nChgCnt = 0;
385 
386  // Attention!
387  // resetting the font here makes it necessary to apply any
388  // changes for extended input directly to the font
389  if ( m_pRedline && m_pRedline->ExtOn() )
390  {
391  m_pRedline->UpdateExtFont( *m_pFont );
392  ++m_nChgCnt;
393  }
394  }
395  }
396 
397  if (m_pTextNode->GetpSwpHints())
398  {
399  if (m_pMergedPara)
400  {
401  // iterate hint by hint: SeekFwd does not mix ends and starts,
402  // it always applies all the starts last, so it must be called once
403  // per position where hints start/end!
404  sal_Int32 nPos(m_nPosition);
405  do
406  {
407  sal_Int32 const nOldPos(nPos);
409  if (nPos <= newPos.second)
410  {
411  SeekFwd(nOldPos, nPos);
412  }
413  else
414  {
415  SeekFwd(nOldPos, newPos.second);
416  }
417  }
418  while (nPos < newPos.second);
419  }
420  else
421  {
422  SeekFwd(m_nPosition, newPos.second);
423  }
424  }
425 
427 
428  if( m_pRedline )
429  m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, m_pTextNode->GetIndex(), newPos.second, m_nPosition);
430  m_nPosition = newPos.second;
431 
432  if( m_nPropFont )
434 
435  return m_pFont->IsFntChg();
436 }
437 
438 static void InsertCharAttrs(SfxPoolItem const** pAttrs, SfxItemSet const& rItems)
439 {
440  SfxItemIter iter(rItems);
441  for (SfxPoolItem const* pItem = iter.GetCurItem(); pItem; pItem = iter.NextItem())
442  {
443  auto const nWhich(pItem->Which());
444  if (isCHRATR(nWhich) && RES_CHRATR_RSID != nWhich)
445  {
446  pAttrs[nWhich - RES_CHRATR_BEGIN] = pItem;
447  }
448  else if (nWhich == RES_TXTATR_UNKNOWN_CONTAINER)
449  {
450  pAttrs[RES_CHRATR_END] = pItem;
451  }
452  }
453 }
454 
455 // if return false: portion ends at start of redline, indexes unchanged
456 // if return true: portion end not known (past end of redline), indexes point to first hint past end of redline
457 static bool CanSkipOverRedline(
458  SwTextNode const& rStartNode, sal_Int32 const nStartRedline,
459  SwRangeRedline const& rRedline,
460  size_t & rStartIndex, size_t & rEndIndex,
461  bool const isTheAnswerYes)
462 {
463  size_t nStartIndex(rStartIndex);
464  size_t nEndIndex(rEndIndex);
465  SwPosition const*const pRLEnd(rRedline.End());
466  if (!pRLEnd->nNode.GetNode().IsTextNode() // if fully deleted...
467  || pRLEnd->nContent == pRLEnd->nNode.GetNode().GetTextNode()->Len())
468  {
469  // shortcut: nothing follows redline
470  // current state is end state
471  return false;
472  }
473  std::vector<SwTextAttr*> activeCharFmts;
474  // can't compare the SwFont that's stored somewhere, it doesn't have compare
475  // operator, so try to recreate the situation with some temp arrays here
476  SfxPoolItem const* activeCharAttrsStart[RES_CHRATR_END - RES_CHRATR_BEGIN + 1] = { nullptr, };
477  if (&rStartNode != &pRLEnd->nNode.GetNode())
478  { // nodes' attributes are only needed if there are different nodes
479  InsertCharAttrs(activeCharAttrsStart, rStartNode.GetSwAttrSet());
480  }
481  if (SwpHints const*const pStartHints = rStartNode.GetpSwpHints())
482  {
483  // check hint ends of hints that start before and end within
484  sal_Int32 const nRedlineEnd(&rStartNode == &pRLEnd->nNode.GetNode()
485  ? pRLEnd->nContent.GetIndex()
486  : rStartNode.Len());
487  for ( ; nEndIndex < pStartHints->Count(); ++nEndIndex)
488  {
489  SwTextAttr *const pAttr(pStartHints->GetSortedByEnd(nEndIndex));
490  if (!pAttr->End())
491  {
492  continue;
493  }
494  if (nRedlineEnd < *pAttr->End())
495  {
496  break;
497  }
498  if (nStartRedline <= pAttr->GetStart())
499  {
500  continue;
501  }
502  if (pAttr->IsFormatIgnoreEnd())
503  {
504  continue;
505  }
506  switch (pAttr->Which())
507  {
508  // if any of these ends inside RL then we need a new portion
509  case RES_TXTATR_REFMARK:
510  case RES_TXTATR_TOXMARK:
511  case RES_TXTATR_META: // actually these 2 aren't allowed to overlap ???
513  case RES_TXTATR_INETFMT:
514  case RES_TXTATR_CJK_RUBY:
516  {
517  if (!isTheAnswerYes) return false; // always break
518  }
519  break;
520  // these are guaranteed not to overlap
521  // and come in order of application
522  case RES_TXTATR_AUTOFMT:
523  case RES_TXTATR_CHARFMT:
524  {
525  if (pAttr->Which() == RES_TXTATR_CHARFMT)
526  {
527  activeCharFmts.push_back(pAttr);
528  }
529  // pure formatting hints may end inside the redline &
530  // start again inside the redline, which must not cause
531  // a new text portion if they have the same items - so
532  // store the effective items & compare all at the end
533  SfxItemSet const& rSet((pAttr->Which() == RES_TXTATR_CHARFMT)
534  ? static_cast<SfxItemSet const&>(pAttr->GetCharFormat().GetCharFormat()->GetAttrSet())
535  : *pAttr->GetAutoFormat().GetStyleHandle());
536  InsertCharAttrs(activeCharAttrsStart, rSet);
537  }
538  break;
539  // SwTextNode::SetAttr puts it into AUTOFMT which is quite
540  // sensible so it doesn't actually exist as a hint
542  default: assert(false);
543  }
544  }
545  assert(nEndIndex == pStartHints->Count() ||
546  pRLEnd->nContent.GetIndex() < pStartHints->GetSortedByEnd(nEndIndex)->GetAnyEnd());
547  }
548 
549  if (&rStartNode != &pRLEnd->nNode.GetNode())
550  {
551  nStartIndex = 0;
552  nEndIndex = 0;
553  }
554 
555  // treat para properties as text properties
556  // ... with the FormatToTextAttr we get autofmts that correspond to the *effective* attr set difference
557  // effective attr set: para props + charfmts + autofmt *in that order*
558  // ... and the charfmt must be *nominally* the same
559 
560  SfxPoolItem const* activeCharAttrsEnd[RES_CHRATR_END - RES_CHRATR_BEGIN + 1] = { nullptr, };
561  if (&rStartNode != &pRLEnd->nNode.GetNode())
562  { // nodes' attributes are only needed if there are different nodes
563  InsertCharAttrs(activeCharAttrsEnd,
564  pRLEnd->nNode.GetNode().GetTextNode()->GetSwAttrSet());
565  }
566 
567  if (SwpHints *const pEndHints = pRLEnd->nNode.GetNode().GetTextNode()->GetpSwpHints())
568  {
569  // check hint starts of hints that start within and end after
570 #ifndef NDEBUG
571  sal_Int32 const nRedlineStart(&rStartNode == &pRLEnd->nNode.GetNode()
572  ? nStartRedline
573  : 0);
574 #endif
575  for ( ; nStartIndex < pEndHints->Count(); ++nStartIndex)
576  {
577  SwTextAttr *const pAttr(pEndHints->Get(nStartIndex));
578  // compare with < here, not <=, to get the effective formatting
579  // of the 1st char after the redline; should not cause problems
580  // with consecutive delete redlines because those are handed by
581  // GetNextRedln() and here we have the last end pos.
582  if (pRLEnd->nContent.GetIndex() < pAttr->GetStart())
583  {
584  break;
585  }
586  if (!pAttr->End())
587  continue;
588  if (pAttr->IsFormatIgnoreStart())
589  {
590  continue;
591  }
592  assert(nRedlineStart <= pAttr->GetStart()); // we wouldn't be here otherwise?
593  if (*pAttr->End() <= pRLEnd->nContent.GetIndex())
594  {
595  continue;
596  }
597  switch (pAttr->Which())
598  {
599  case RES_TXTATR_REFMARK:
600  case RES_TXTATR_TOXMARK:
601  case RES_TXTATR_META: // actually these 2 aren't allowed to overlap ???
603  case RES_TXTATR_INETFMT:
604  case RES_TXTATR_CJK_RUBY:
606  {
607  if (!isTheAnswerYes) return false;
608  }
609  break;
610  case RES_TXTATR_AUTOFMT:
611  case RES_TXTATR_CHARFMT:
612  {
613  // char formats must be *nominally* the same
614  if (pAttr->Which() == RES_TXTATR_CHARFMT)
615  {
616  auto iter = std::find_if(activeCharFmts.begin(), activeCharFmts.end(),
617  [&pAttr](const SwTextAttr* pCharFmt) { return *pCharFmt == *pAttr; });
618  if (iter != activeCharFmts.end())
619  activeCharFmts.erase(iter);
620  else if (!isTheAnswerYes)
621  return false;
622  }
623  SfxItemSet const& rSet((pAttr->Which() == RES_TXTATR_CHARFMT)
624  ? static_cast<SfxItemSet const&>(pAttr->GetCharFormat().GetCharFormat()->GetAttrSet())
625  : *pAttr->GetAutoFormat().GetStyleHandle());
626  InsertCharAttrs(activeCharAttrsEnd, rSet);
627 
628  }
629  break;
630  // SwTextNode::SetAttr puts it into AUTOFMT which is quite
631  // sensible so it doesn't actually exist as a hint
633  default: assert(false);
634  }
635  }
636  if (&rStartNode != &pRLEnd->nNode.GetNode())
637  {
638  // need to iterate the nEndIndex forward too so the loop in the
639  // caller can look for the right ends in the next iteration
640  for (nEndIndex = 0; nEndIndex < pEndHints->Count(); ++nEndIndex)
641  {
642  SwTextAttr *const pAttr(pEndHints->GetSortedByEnd(nEndIndex));
643  if (!pAttr->End())
644  continue;
645  if (pRLEnd->nContent.GetIndex() < *pAttr->End())
646  {
647  break;
648  }
649  }
650  }
651  }
652 
653  // if we didn't find a matching start for any end, then it really ends inside
654  if (!activeCharFmts.empty())
655  {
656  if (!isTheAnswerYes) return false;
657  }
658  for (size_t i = 0; i < SAL_N_ELEMENTS(activeCharAttrsStart); ++i)
659  {
660  // all of these are poolable
661 // assert(!activeCharAttrsStart[i] || activeCharAttrsStart[i]->GetItemPool()->IsItemPoolable(*activeCharAttrsStart[i]));
662  if (activeCharAttrsStart[i] != activeCharAttrsEnd[i])
663  {
664  if (!isTheAnswerYes) return false;
665  }
666  }
667  rStartIndex = nStartIndex;
668  rEndIndex = nEndIndex;
669  return true;
670 }
671 
672 static sal_Int32 GetNextAttrImpl(SwTextNode const*const pTextNode,
673  size_t const nStartIndex, size_t const nEndIndex,
674  sal_Int32 const nPosition)
675 {
676  // note: this used to be COMPLETE_STRING, but was set to Len() + 1 below,
677  // which is rather silly, so set it to Len() instead
678  sal_Int32 nNext = pTextNode->Len();
679  if (SwpHints const*const pHints = pTextNode->GetpSwpHints())
680  {
681  // are there attribute starts left?
682  for (size_t i = nStartIndex; i < pHints->Count(); ++i)
683  {
684  SwTextAttr *const pAttr(pHints->Get(i));
685  if (!pAttr->IsFormatIgnoreStart())
686  {
687  nNext = pAttr->GetStart();
688  break;
689  }
690  }
691  // are there attribute ends left?
692  for (size_t i = nEndIndex; i < pHints->Count(); ++i)
693  {
694  SwTextAttr *const pAttr(pHints->GetSortedByEnd(i));
695  if (!pAttr->IsFormatIgnoreEnd())
696  {
697  sal_Int32 const nNextEnd = pAttr->GetAnyEnd();
698  nNext = std::min(nNext, nNextEnd); // pick nearest one
699  break;
700  }
701  }
702  }
703  // TODO: maybe use hints like FieldHints for this instead of looking at the text...
704  const sal_Int32 l = std::min(nNext, pTextNode->Len());
705  sal_Int32 p = nPosition;
706  const sal_Unicode* pStr = pTextNode->GetText().getStr();
707  while (p < l)
708  {
709  sal_Unicode aChar = pStr[p];
710  switch (aChar)
711  {
714  case CH_TXT_ATR_FIELDSEP:
715  case CH_TXT_ATR_FIELDEND:
716  goto break_; // sigh...
717  default:
718  ++p;
719  }
720  }
721 break_:
722  assert(p <= nNext);
723  if (p < l)
724  {
725  // found a CH_TXT_ATR_FIELD*: if it's same as current position,
726  // skip behind it so that both before- and after-positions are returned
727  nNext = (nPosition < p) ? p : p + 1;
728  }
729  return nNext;
730 }
731 
733 {
734  size_t nStartIndex(m_nStartIndex);
735  size_t nEndIndex(m_nEndIndex);
736  size_t nPosition(m_nPosition);
737  SwTextNode const* pTextNode(m_pTextNode);
739 
740  while (true)
741  {
742  sal_Int32 nNext = GetNextAttrImpl(pTextNode, nStartIndex, nEndIndex, nPosition);
743  if( m_pRedline )
744  {
745  std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>> const redline(
746  m_pRedline->GetNextRedln(nNext, pTextNode, nActRedline));
747  if (redline.second.first)
748  {
749  assert(m_pMergedPara);
750  assert(redline.second.first->End()->nNode.GetIndex() <= m_pMergedPara->pLastNode->GetIndex()
751  || !redline.second.first->End()->nNode.GetNode().IsTextNode());
752  if (CanSkipOverRedline(*pTextNode, redline.first, *redline.second.first,
753  nStartIndex, nEndIndex, m_nPosition == redline.first))
754  { // if current position is start of the redline, must skip!
755  nActRedline += redline.second.second;
756  if (&redline.second.first->End()->nNode.GetNode() != pTextNode)
757  {
758  pTextNode = redline.second.first->End()->nNode.GetNode().GetTextNode();
759  nPosition = redline.second.first->End()->nContent.GetIndex();
760  }
761  else
762  {
763  nPosition = redline.second.first->End()->nContent.GetIndex();
764  }
765  }
766  else
767  {
768  return sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first);
769  }
770  }
771  else
772  {
773  return m_pMergedPara
774  ? sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first)
775  : TextFrameIndex(redline.first);
776  }
777  }
778  else
779  {
780  return TextFrameIndex(nNext);
781  }
782  }
783 }
784 
786 {
787 public:
789  SwViewShell const * pSh;
792  long nRowWidth;
794  long nWordAdd;
795  sal_Int32 nNoLineBreak;
796  SwMinMaxArgs( OutputDevice* pOutI, SwViewShell const * pShI, sal_uLong& rMinI, sal_uLong &rAbsI )
797  : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rAbsMin( rAbsI )
798  { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = COMPLETE_STRING; }
799  void Minimum( long nNew ) const { if( static_cast<long>(rMin) < nNew ) rMin = nNew; }
800  void NewWord() { nWordAdd = nWordWidth = 0; }
801 };
802 
803 static bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const OUString &rText,
804  sal_Int32 nIdx, sal_Int32 nEnd )
805 {
806  bool bRet = false;
807  while( nIdx < nEnd )
808  {
809  sal_Int32 nStop = nIdx;
810  LanguageType eLang = pFnt->GetLanguage();
811  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
812 
813  bool bClear = CH_BLANK == rText[ nStop ];
814  Boundary aBndry( g_pBreakIt->GetBreakIter()->getWordBoundary( rText, nIdx,
815  g_pBreakIt->GetLocale( eLang ),
816  WordType::DICTIONARY_WORD, true ) );
817  nStop = aBndry.endPos;
818  if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
819  rArg.NewWord();
820  if( nStop == nIdx )
821  ++nStop;
822  if( nStop > nEnd )
823  nStop = nEnd;
824 
825  SwDrawTextInfo aDrawInf(rArg.pSh, *rArg.pOut, rText, nIdx, nStop - nIdx);
826  long nCurrentWidth = pFnt->GetTextSize_( aDrawInf ).Width();
827  rArg.nRowWidth += nCurrentWidth;
828  if( bClear )
829  rArg.NewWord();
830  else
831  {
832  rArg.nWordWidth += nCurrentWidth;
833  if( static_cast<long>(rArg.rAbsMin) < rArg.nWordWidth )
834  rArg.rAbsMin = rArg.nWordWidth;
835  rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
836  bRet = true;
837  }
838  nIdx = nStop;
839  }
840  return bRet;
841 }
842 
843 bool SwTextNode::IsSymbolAt(const sal_Int32 nBegin) const
844 {
845  SwScriptInfo aScriptInfo;
846  SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
847  aIter.Seek( TextFrameIndex(nBegin) );
848  return aIter.GetFnt()->IsSymbol( getIDocumentLayoutAccess().GetCurrentViewShell() );
849 }
850 
852 {
853 public:
854  sal_uLong nMaxWidth; // sum of all frame widths
855  long nMinWidth; // biggest frame
856  long nLeftRest; // space not already covered by frames in the left margin
857  long nRightRest; // space not already covered by frames in the right margin
858  long nLeftDiff; // Min/Max-difference of the frame in the left margin
859  long nRightDiff; // Min/Max-difference of the frame in the right margin
860  sal_uLong nIndx; // index of the node
861  void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
862 };
863 
865 {
866  const SwFormatAnchor& rFormatA = pNd->GetAnchor();
867 
868  if ((RndStdIds::FLY_AT_PARA != rFormatA.GetAnchorId()) &&
869  (RndStdIds::FLY_AT_CHAR != rFormatA.GetAnchorId()))
870  {
871  return;
872  }
873 
874  const SwPosition *pPos = rFormatA.GetContentAnchor();
875  OSL_ENSURE(pPos && pIn, "Unexpected NULL arguments");
876  if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
877  return;
878 
879  long nMin, nMax;
880  SwHTMLTableLayout *pLayout = nullptr;
881  const bool bIsDrawFrameFormat = pNd->Which()==RES_DRAWFRMFMT;
882  if( !bIsDrawFrameFormat )
883  {
884  // Does the frame contain a table at the start or the end?
885  const SwNodes& rNodes = pNd->GetDoc()->GetNodes();
886  const SwFormatContent& rFlyContent = pNd->GetContent();
887  sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
888  SwTableNode* pTableNd = rNodes[nStt+1]->GetTableNode();
889  if( !pTableNd )
890  {
891  SwNode *pNd2 = rNodes[nStt];
892  pNd2 = rNodes[pNd2->EndOfSectionIndex()-1];
893  if( pNd2->IsEndNode() )
894  pTableNd = pNd2->StartOfSectionNode()->GetTableNode();
895  }
896 
897  if( pTableNd )
898  pLayout = pTableNd->GetTable().GetHTMLTableLayout();
899  }
900 
901  const SwFormatHoriOrient& rOrient = pNd->GetHoriOrient();
902  sal_Int16 eHoriOri = rOrient.GetHoriOrient();
903 
904  long nDiff;
905  if( pLayout )
906  {
907  nMin = pLayout->GetMin();
908  nMax = pLayout->GetMax();
909  nDiff = nMax - nMin;
910  }
911  else
912  {
913  if( bIsDrawFrameFormat )
914  {
915  const SdrObject* pSObj = pNd->FindSdrObject();
916  if( pSObj )
917  nMin = pSObj->GetCurrentBoundRect().GetWidth();
918  else
919  nMin = 0;
920 
921  }
922  else
923  {
924  const SwFormatFrameSize &rSz = pNd->GetFrameSize();
925  nMin = rSz.GetWidth();
926  }
927  nMax = nMin;
928  nDiff = 0;
929  }
930 
931  const SvxLRSpaceItem &rLR = pNd->GetLRSpace();
932  nMin += rLR.GetLeft();
933  nMin += rLR.GetRight();
934  nMax += rLR.GetLeft();
935  nMax += rLR.GetRight();
936 
937  if( css::text::WrapTextMode_THROUGH == pNd->GetSurround().GetSurround() )
938  {
939  pIn->Minimum( nMin );
940  return;
941  }
942 
943  // Frames, which are left- or right-aligned are only party considered
944  // when calculating the maximum, since the border is already being considered.
945  // Only if the frame extends into the text body, this part is being added
946  switch( eHoriOri )
947  {
948  case text::HoriOrientation::RIGHT:
949  {
950  if( nDiff )
951  {
952  pIn->nRightRest -= pIn->nRightDiff;
953  pIn->nRightDiff = nDiff;
954  }
955  if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
956  {
957  if( pIn->nRightRest > 0 )
958  pIn->nRightRest = 0;
959  }
960  pIn->nRightRest -= nMin;
961  break;
962  }
963  case text::HoriOrientation::LEFT:
964  {
965  if( nDiff )
966  {
967  pIn->nLeftRest -= pIn->nLeftDiff;
968  pIn->nLeftDiff = nDiff;
969  }
970  if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
971  pIn->nLeftRest < 0 )
972  pIn->nLeftRest = 0;
973  pIn->nLeftRest -= nMin;
974  break;
975  }
976  default:
977  {
978  pIn->nMaxWidth += nMax;
979  pIn->Minimum( nMin );
980  }
981  }
982 }
983 
984 #define FLYINCNT_MIN_WIDTH 284
985 
991  sal_uLong& rAbsMin ) const
992 {
994  OutputDevice* pOut = nullptr;
995  if( pSh )
996  pOut = pSh->GetWin();
997  if( !pOut )
999 
1000  MapMode aOldMap( pOut->GetMapMode() );
1001  pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
1002 
1003  rMin = 0;
1004  rMax = 0;
1005  rAbsMin = 0;
1006 
1007  const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
1008  long nLROffset = rSpace.GetTextLeft() + GetLeftMarginWithNum( true );
1009  short nFLOffs;
1010  // For enumerations a negative first line indentation is probably filled already
1011  if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
1012  nLROffset = nFLOffs;
1013 
1014  SwMinMaxNodeArgs aNodeArgs;
1015  aNodeArgs.nMinWidth = 0;
1016  aNodeArgs.nMaxWidth = 0;
1017  aNodeArgs.nLeftRest = nLROffset;
1018  aNodeArgs.nRightRest = rSpace.GetRight();
1019  aNodeArgs.nLeftDiff = 0;
1020  aNodeArgs.nRightDiff = 0;
1021  if( nIndex )
1022  {
1023  SwFrameFormats* pTmp = const_cast<SwFrameFormats*>(GetDoc()->GetSpzFrameFormats());
1024  if( pTmp )
1025  {
1026  aNodeArgs.nIndx = nIndex;
1027  for( SwFrameFormat *pFormat : *pTmp )
1028  lcl_MinMaxNode( pFormat, &aNodeArgs );
1029  }
1030  }
1031  if( aNodeArgs.nLeftRest < 0 )
1032  aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
1033  aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
1034  if( aNodeArgs.nLeftRest < 0 )
1035  aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
1036 
1037  if( aNodeArgs.nRightRest < 0 )
1038  aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
1039  aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
1040  if( aNodeArgs.nRightRest < 0 )
1041  aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
1042 
1043  SwScriptInfo aScriptInfo;
1044  SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
1045  TextFrameIndex nIdx(0);
1046  aIter.SeekAndChgAttrIter( nIdx, pOut );
1047  TextFrameIndex nLen(m_Text.getLength());
1048  long nCurrentWidth = 0;
1049  long nAdd = 0;
1050  SwMinMaxArgs aArg( pOut, pSh, rMin, rAbsMin );
1051  while( nIdx < nLen )
1052  {
1053  TextFrameIndex nNextChg = aIter.GetNextAttr();
1054  TextFrameIndex nStop = aScriptInfo.NextScriptChg( nIdx );
1055  if( nNextChg > nStop )
1056  nNextChg = nStop;
1057  SwTextAttr *pHint = nullptr;
1058  sal_Unicode cChar = CH_BLANK;
1059  nStop = nIdx;
1060  while( nStop < nLen && nStop < nNextChg &&
1061  CH_TAB != (cChar = m_Text[sal_Int32(nStop)]) &&
1062  CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
1063  CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
1064  !pHint )
1065  {
1066  if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
1067  || ( nullptr == ( pHint = aIter.GetAttr( nStop ) ) ) )
1068  ++nStop;
1069  }
1070  if (lcl_MinMaxString(aArg, aIter.GetFnt(), m_Text, sal_Int32(nIdx), sal_Int32(nStop)))
1071  {
1072  nAdd = 20;
1073  }
1074  nIdx = nStop;
1075  aIter.SeekAndChgAttrIter( nIdx, pOut );
1076  switch( cChar )
1077  {
1078  case CH_BREAK :
1079  {
1080  if( static_cast<long>(rMax) < aArg.nRowWidth )
1081  rMax = aArg.nRowWidth;
1082  aArg.nRowWidth = 0;
1083  aArg.NewWord();
1084  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1085  }
1086  break;
1087  case CH_TAB :
1088  {
1089  aArg.NewWord();
1090  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1091  }
1092  break;
1093  case CHAR_SOFTHYPHEN:
1094  ++nIdx;
1095  break;
1096  case CHAR_HARDBLANK:
1097  case CHAR_HARDHYPHEN:
1098  {
1099  OUString sTmp( cChar );
1100  SwDrawTextInfo aDrawInf( pSh,
1101  *pOut, sTmp, 0, 1, 0, false );
1102  nCurrentWidth = aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1103  aArg.nWordWidth += nCurrentWidth;
1104  aArg.nRowWidth += nCurrentWidth;
1105  if( static_cast<long>(rAbsMin) < aArg.nWordWidth )
1106  rAbsMin = aArg.nWordWidth;
1107  aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
1108  aArg.nNoLineBreak = sal_Int32(nIdx++);
1109  }
1110  break;
1111  case CH_TXTATR_BREAKWORD:
1112  case CH_TXTATR_INWORD:
1113  {
1114  if( !pHint )
1115  break;
1116  long nOldWidth = aArg.nWordWidth;
1117  long nOldAdd = aArg.nWordAdd;
1118  aArg.NewWord();
1119 
1120  switch( pHint->Which() )
1121  {
1122  case RES_TXTATR_FLYCNT :
1123  {
1124  SwFrameFormat *pFrameFormat = pHint->GetFlyCnt().GetFrameFormat();
1125  const SvxLRSpaceItem &rLR = pFrameFormat->GetLRSpace();
1126  if( RES_DRAWFRMFMT == pFrameFormat->Which() )
1127  {
1128  const SdrObject* pSObj = pFrameFormat->FindSdrObject();
1129  if( pSObj )
1130  nCurrentWidth = pSObj->GetCurrentBoundRect().GetWidth();
1131  else
1132  nCurrentWidth = 0;
1133  }
1134  else
1135  {
1136  const SwFormatFrameSize& rTmpSize = pFrameFormat->GetFrameSize();
1137  if( RES_FLYFRMFMT == pFrameFormat->Which()
1138  && rTmpSize.GetWidthPercent() )
1139  {
1140  // This is a hack for the following situation: In the paragraph there's a
1141  // text frame with relative size. Then let's take 0.5 cm as minimum width
1142  // and USHRT_MAX as maximum width
1143  // It were cleaner and maybe necessary later on to iterate over the content
1144  // of the text frame and call GetMinMaxSize recursively
1145  nCurrentWidth = FLYINCNT_MIN_WIDTH; // 0.5 cm
1146  rMax = std::max(rMax, sal_uLong(USHRT_MAX));
1147  }
1148  else
1149  nCurrentWidth = pFrameFormat->GetFrameSize().GetWidth();
1150  }
1151  nCurrentWidth += rLR.GetLeft();
1152  nCurrentWidth += rLR.GetRight();
1153  aArg.nWordAdd = nOldWidth + nOldAdd;
1154  aArg.nWordWidth = nCurrentWidth;
1155  aArg.nRowWidth += nCurrentWidth;
1156  if( static_cast<long>(rAbsMin) < aArg.nWordWidth )
1157  rAbsMin = aArg.nWordWidth;
1158  aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
1159  break;
1160  }
1161  case RES_TXTATR_FTN :
1162  {
1163  const OUString aText = pHint->GetFootnote().GetNumStr();
1164  if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
1165  aText.getLength() ) )
1166  nAdd = 20;
1167  break;
1168  }
1169 
1170  case RES_TXTATR_FIELD :
1171  case RES_TXTATR_ANNOTATION :
1172  {
1173  SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
1174  const OUString aText = pField->ExpandField(true, nullptr);
1175  if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
1176  aText.getLength() ) )
1177  nAdd = 20;
1178  break;
1179  }
1180  default: aArg.nWordWidth = nOldWidth;
1181  aArg.nWordAdd = nOldAdd;
1182 
1183  }
1184  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1185  }
1186  break;
1187  }
1188  }
1189  if( static_cast<long>(rMax) < aArg.nRowWidth )
1190  rMax = aArg.nRowWidth;
1191 
1192  nLROffset += rSpace.GetRight();
1193 
1194  rAbsMin += nLROffset;
1195  rAbsMin += nAdd;
1196  rMin += nLROffset;
1197  rMin += nAdd;
1198  if( static_cast<long>(rMin) < aNodeArgs.nMinWidth )
1199  rMin = aNodeArgs.nMinWidth;
1200  if( static_cast<long>(rAbsMin) < aNodeArgs.nMinWidth )
1201  rAbsMin = aNodeArgs.nMinWidth;
1202  rMax += aNodeArgs.nMaxWidth;
1203  rMax += nLROffset;
1204  rMax += nAdd;
1205  if( rMax < rMin ) // e.g. Frames with flow through only contribute to the minimum
1206  rMax = rMin;
1207  pOut->SetMapMode( aOldMap );
1208 }
1209 
1220  TextFrameIndex nStart, TextFrameIndex nEnd)
1221 {
1222  assert(GetOfst() <= nStart && (!GetFollow() || nStart < GetFollow()->GetOfst()));
1223  SwViewShell const*const pSh = getRootFrame()->GetCurrShell();
1224  assert(pSh);
1225  OutputDevice *const pOut = &pSh->GetRefDev();
1226  assert(pOut);
1227 
1228  MapMode aOldMap( pOut->GetMapMode() );
1229  pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
1230 
1231  if (nStart == nEnd)
1232  {
1233  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
1234 
1235  SwScriptInfo aScriptInfo;
1236  SwAttrIter aIter(*GetTextNodeFirst(), aScriptInfo, this);
1237  aIter.SeekAndChgAttrIter( nStart, pOut );
1238 
1239  Boundary aBound = g_pBreakIt->GetBreakIter()->getWordBoundary(
1240  GetText(), sal_Int32(nStart),
1241  g_pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
1242  WordType::DICTIONARY_WORD, true );
1243 
1244  if (sal_Int32(nStart) == aBound.startPos)
1245  {
1246  // cursor is at left or right border of word
1247  pOut->SetMapMode( aOldMap );
1248  return 100;
1249  }
1250 
1251  nStart = TextFrameIndex(aBound.startPos);
1252  nEnd = TextFrameIndex(aBound.endPos);
1253 
1254  if (nStart == nEnd)
1255  {
1256  pOut->SetMapMode( aOldMap );
1257  return 100;
1258  }
1259  }
1260 
1261  SwScriptInfo aScriptInfo;
1262  SwAttrIter aIter(*GetTextNodeFirst(), aScriptInfo, this);
1263 
1264  // We do not want scaling attributes to be considered during this
1265  // calculation. For this, we push a temporary scaling attribute with
1266  // scaling value 100 and priority flag on top of the scaling stack
1267  SwAttrHandler& rAH = aIter.GetAttrHandler();
1269  SwTextAttrEnd aAttr( aItem, 0, COMPLETE_STRING );
1270  aAttr.SetPriorityAttr( true );
1271  rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
1272 
1273  TextFrameIndex nIdx = nStart;
1274 
1275  sal_uLong nWidth = 0;
1276  sal_uLong nProWidth = 0;
1277 
1278  while( nIdx < nEnd )
1279  {
1280  aIter.SeekAndChgAttrIter( nIdx, pOut );
1281 
1282  // scan for end of portion
1283  TextFrameIndex const nNextChg = std::min(aIter.GetNextAttr(), aScriptInfo.NextScriptChg(nIdx));
1284 
1285  TextFrameIndex nStop = nIdx;
1286  sal_Unicode cChar = CH_BLANK;
1287  SwTextAttr* pHint = nullptr;
1288 
1289  // stop at special characters in [ nIdx, nNextChg ]
1290  while( nStop < nEnd && nStop < nNextChg )
1291  {
1292  cChar = GetText()[sal_Int32(nStop)];
1293  if (
1294  CH_TAB == cChar ||
1295  CH_BREAK == cChar ||
1296  CHAR_HARDBLANK == cChar ||
1297  CHAR_HARDHYPHEN == cChar ||
1298  CHAR_SOFTHYPHEN == cChar ||
1299  (
1300  (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
1301  (nullptr == (pHint = aIter.GetAttr(nStop)))
1302  )
1303  )
1304  {
1305  break;
1306  }
1307  else
1308  ++nStop;
1309  }
1310 
1311  // calculate text widths up to cChar
1312  if ( nStop > nIdx )
1313  {
1314  SwDrawTextInfo aDrawInf(pSh, *pOut, GetText(), sal_Int32(nIdx), sal_Int32(nStop - nIdx));
1315  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1316  }
1317 
1318  nIdx = nStop;
1319  aIter.SeekAndChgAttrIter( nIdx, pOut );
1320 
1321  if ( cChar == CH_BREAK )
1322  {
1323  nWidth = std::max( nWidth, nProWidth );
1324  nProWidth = 0;
1325  nIdx++;
1326  }
1327  else if ( cChar == CH_TAB )
1328  {
1329  // tab receives width of one space
1330  OUString sTmp( CH_BLANK );
1331  SwDrawTextInfo aDrawInf(pSh, *pOut, sTmp, 0, 1);
1332  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1333  nIdx++;
1334  }
1335  else if ( cChar == CHAR_SOFTHYPHEN )
1336  ++nIdx;
1337  else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
1338  {
1339  OUString sTmp( cChar );
1340  SwDrawTextInfo aDrawInf(pSh, *pOut, sTmp, 0, 1);
1341  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1342  nIdx++;
1343  }
1344  else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || cChar == CH_TXTATR_INWORD ) )
1345  {
1346  switch( pHint->Which() )
1347  {
1348  case RES_TXTATR_FTN :
1349  {
1350  const OUString aText = pHint->GetFootnote().GetNumStr();
1351  SwDrawTextInfo aDrawInf(pSh, *pOut, aText, 0, aText.getLength());
1352 
1353  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1354  break;
1355  }
1356 
1357  case RES_TXTATR_FIELD :
1358  case RES_TXTATR_ANNOTATION :
1359  {
1360  SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
1361  OUString const aText = pField->ExpandField(true, getRootFrame());
1362  SwDrawTextInfo aDrawInf(pSh, *pOut, aText, 0, aText.getLength());
1363 
1364  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1365  break;
1366  }
1367 
1368  default:
1369  {
1370  // any suggestions for a default action?
1371  }
1372  } // end of switch
1373  nIdx++;
1374  } // end of while
1375  }
1376 
1377  nWidth = std::max( nWidth, nProWidth );
1378 
1379  // search for the line containing nStart
1380  if (HasPara())
1381  {
1382  SwTextInfo aInf(this);
1383  SwTextIter aLine(this, &aInf);
1384  aLine.CharToLine( nStart );
1385  pOut->SetMapMode( aOldMap );
1386  return static_cast<sal_uInt16>( nWidth ?
1387  ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1388  }
1389  // no frame or no paragraph, we take the height of the character
1390  // at nStart as line height
1391 
1392  aIter.SeekAndChgAttrIter( nStart, pOut );
1393  pOut->SetMapMode( aOldMap );
1394 
1395  SwDrawTextInfo aDrawInf(pSh, *pOut, GetText(), sal_Int32(nStart), 1);
1396  return static_cast<sal_uInt16>( nWidth ? ((100 * aIter.GetFnt()->GetTextSize_( aDrawInf ).Height()) / nWidth ) : 0 );
1397 }
1398 
1400 {
1401  SwTwips nRet = 0;
1402 
1403  sal_Int32 nIdx = 0;
1404 
1405  while ( nIdx < GetText().getLength() )
1406  {
1407  const sal_Unicode cCh = GetText()[nIdx];
1408  if ( cCh!='\t' && cCh!=' ' )
1409  {
1410  break;
1411  }
1412  ++nIdx;
1413  }
1414 
1415  if ( nIdx > 0 )
1416  {
1417  SwPosition aPos( *this );
1418  aPos.nContent += nIdx;
1419 
1420  // Find the non-follow text frame:
1422  for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1423  {
1424  // Only consider master frames:
1425  if (!pFrame->IsFollow() &&
1426  pFrame->GetTextNodeForFirstText() == this)
1427  {
1428  SwRectFnSet aRectFnSet(pFrame);
1429  SwRect aRect;
1430  pFrame->GetCharRect( aRect, aPos );
1431  nRet = pFrame->IsRightToLeft() ?
1432  aRectFnSet.GetPrtRight(*pFrame) - aRectFnSet.GetRight(aRect) :
1433  aRectFnSet.GetLeft(aRect) - aRectFnSet.GetPrtLeft(*pFrame);
1434  break;
1435  }
1436  }
1437  }
1438 
1439  return nRet;
1440 }
1441 
1442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long GetLeft() const
SwAttrHandler & GetAttrHandler()
Definition: itratr.hxx:109
long Width() const
SwScriptInfo * m_pScriptInfo
Definition: itratr.hxx:40
sal_uLong GetMin() const
Definition: htmltbl.hxx:280
const sal_Unicode CH_BREAK
Definition: swfont.hxx:43
bool SeekAndChgAttrIter(TextFrameIndex nPos, OutputDevice *pOut)
Executes ChgPhysFnt if Seek() returns true and change font to merge character border with neighbours...
Definition: itratr.cxx:155
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:44
long GetWidth() const
SwFontScript WhichFont(TextFrameIndex nIdx) const
Definition: porlay.cxx:724
sal_uLong GetIndex() const
Definition: node.hxx:282
SwViewShell const * pSh
Definition: itratr.cxx:789
Marks a position in the document model.
Definition: pam.hxx:35
virtual const tools::Rectangle & GetCurrentBoundRect() const
bool MaybeHasHints() const
Definition: itratr.cxx:127
TextFrameIndex NextScriptChg(TextFrameIndex nPos) const
Definition: porlay.cxx:1426
const SwField * GetField() const
Definition: fmtfld.hxx:70
long GetLeftMarginWithNum(bool bTextLeft=false) const
Returns the additional indents of this text node and its numbering.
Definition: ndtxt.cxx:3161
bool isCHRATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:343
sal_uInt16 Height() const
Definition: possiz.hxx:44
#define RES_TXTATR_CJK_RUBY
Definition: hintids.hxx:144
const OUString & GetText() const
Definition: ndtxt.hxx:210
void PopAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:425
SwTextAttr * GetAttr(TextFrameIndex nPos) const
Returns the attribute for a position.
Definition: itratr.cxx:147
#define RES_TXTATR_METAFIELD
Definition: hintids.hxx:140
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:218
#define FLYINCNT_MIN_WIDTH
Definition: itratr.cxx:984
bool HasPara() const
Definition: txtfrm.hxx:808
long nWordAdd
Definition: itratr.cxx:794
static bool lcl_MinMaxString(SwMinMaxArgs &rArg, SwFont *pFnt, const OUString &rText, sal_Int32 nIdx, sal_Int32 nEnd)
Definition: itratr.cxx:803
long Height() const
SwNodeIndex nNode
Definition: pam.hxx:37
long GetWidth() const
void SetPriorityAttr(bool bFlag)
Definition: txatbase.hxx:98
const SwTextNode * m_pTextNode
input: the current text node
Definition: itratr.hxx:57
bool GetFirstLineOfsWithNum(short &rFirstOffset) const
Returns the combined first line indent of this text node and its numbering.
Definition: ndtxt.cxx:3204
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
sal_uIntPtr sal_uLong
size_t m_nEndIndex
current iteration index in HintEnds
Definition: itratr.hxx:50
Base class of all fields.
Definition: fldbas.hxx:280
Size GetTextSize_(SwDrawTextInfo &rInf)
Definition: swfont.hxx:309
void SeekFwd(sal_Int32 nOldPos, sal_Int32 nNewPos)
Definition: itratr.cxx:263
TElementType * Next()
Definition: calbck.hxx:373
#define RES_TXTATR_UNKNOWN_CONTAINER
Definition: hintids.hxx:145
TextFrameIndex GetOfst() const
Definition: txtfrm.hxx:426
#define CHAR_HARDBLANK
Definition: swtypes.hxx:172
const MapMode & GetMapMode() const
TextFrameIndex GetNextAttr() const
Definition: itratr.cxx:732
SwFont * m_pFont
Definition: itratr.hxx:39
long SwTwips
Definition: swtypes.hxx:49
SwTwips GetWidthOfLeadingTabs() const
Returns the width of leading tabs/blanks in this paragraph.
Definition: itratr.cxx:1399
void CharToLine(TextFrameIndex)
Definition: itrtxt.cxx:194
Content, content of frame (header, footer, fly).
Definition: fmtcntnt.hxx:31
bool IsSymbol(SwViewShell const *pSh)
Definition: swfont.hxx:269
void ResetFont(SwFont &rFnt) const
Definition: atrhndl.hxx:106
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
#define RES_TXTATR_CHARFMT
Definition: hintids.hxx:143
sal_uInt16 Which() const
Definition: txatbase.hxx:110
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1290
sal_Int32 GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:153
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:50
void SetMapMode()
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:737
bool Seek(TextFrameIndex nPos)
Enables the attributes used at char pos nPos in the logical font.
Definition: itratr.cxx:305
bool IsSymbolAt(sal_Int32 nBegin) const
in ndcopy.cxx
Definition: itratr.cxx:843
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:174
static OutputDevice * GetDefaultDevice()
sal_Int32 m_nPosition
current iteration index in text node
Definition: itratr.hxx:52
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:43
#define RES_TXTATR_META
Definition: hintids.hxx:139
sal_uInt16 sal_Unicode
#define RES_CHRATR_END
Definition: hintids.hxx:115
const SfxPoolItem * NextItem()
#define CH_TXTATR_INWORD
Definition: hintids.hxx:44
SwTableNode * GetTableNode()
Definition: node.hxx:599
SwAttrIter(SwTextNode const *pTextNode)
Definition: itratr.cxx:71
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
SwMinMaxArgs(OutputDevice *pOutI, SwViewShell const *pShI, sal_uLong &rMinI, sal_uLong &rAbsI)
Definition: itratr.cxx:796
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
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
void SetFntChg(const bool bNew)
Definition: swfont.hxx:208
const SwTable & GetTable() const
Definition: node.hxx:497
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
const OUString & GetNumStr() const
Definition: fmtftn.hxx:71
long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1355
long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1356
sal_uLong GetMax() const
Definition: htmltbl.hxx:281
bool SeekStartAndChgAttrIter(OutputDevice *pOut, const bool bParaFont)
Definition: itratr.cxx:197
void ChgPhysFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.cxx:972
std::unique_ptr< SwRedlineItr, o3tl::default_delete< SwRedlineItr > > m_pRedline
Definition: itratr.hxx:46
SwFontScript GetActual() const
Definition: swfont.hxx:183
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:844
Specific frame formats (frames, DrawObjects).
Definition: docary.hxx:201
vcl::RenderContext & GetRefDev() const
Definition: viewsh.cxx:2080
bool IsFntChg() const
Definition: swfont.hxx:207
#define SAL_N_ELEMENTS(arr)
void Minimum(long nNew) const
Definition: itratr.cxx:799
void InitFontAndAttrHandler(SwTextNode const &rPropsNode, SwTextNode const &rTextNode, OUString const &rText, bool const *pbVertLayout, bool const *pbVertLayoutLRBT)
Definition: redlnitr.cxx:307
#define RES_FLYFRMFMT
Definition: hintids.hxx:276
sw::MergedPara const * m_pMergedPara
Definition: itratr.hxx:58
SwTextNode * GetTextNodeFirst()
Definition: txtfrm.hxx:445
Style of a layout element.
Definition: frmfmt.hxx:57
void Reset()
Definition: atrstck.cxx:334
void Minimum(long nNew)
Definition: itratr.cxx:861
sal_uLong & rAbsMin
Definition: itratr.cxx:791
long nWordWidth
Definition: itratr.cxx:793
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:131
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
#define RES_TXTATR_FTN
Definition: hintids.hxx:153
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:108
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
const sal_Unicode CH_TAB
Definition: swfont.hxx:44
long nRowWidth
Definition: itratr.cxx:792
VclPtr< OutputDevice > pOut
Definition: itratr.cxx:788
Count
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1182
TElementType * First()
Definition: calbck.hxx:342
int i
vector_type::size_type size_type
Definition: docary.hxx:330
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
FlyAnchors.
Definition: fmtanchr.hxx:34
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(MergedPara const &, TextFrameIndex nIndex)
Definition: txtfrm.cxx:1163
SwDoc * GetDoc()
Definition: node.hxx:702
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:52
#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
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
css::text::WrapTextMode GetSurround() const
Definition: fmtsrnd.hxx:51
SwFont * GetFnt()
Definition: itratr.hxx:103
#define RES_TXTATR_TOXMARK
Definition: hintids.hxx:138
bool IsEndNode() const
Definition: node.hxx:632
static void lcl_MinMaxNode(SwFrameFormat *pNd, SwMinMaxNodeArgs *pIn)
Definition: itratr.cxx:864
OUString mergedText
note: cannot be const currently to avoid UB because SwTextGuess::Guess const_casts it and modifies it...
Definition: txtfrm.hxx:960
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:119
sal_uInt8 GetWidthPercent() const
Definition: fmtfsize.hxx:91
static bool CanSkipOverRedline(SwTextNode const &rStartNode, sal_Int32 const nStartRedline, SwRangeRedline const &rRedline, size_t &rStartIndex, size_t &rEndIndex, bool const isTheAnswerYes)
Definition: itratr.cxx:457
#define RES_TXTATR_INETFMT
Definition: hintids.hxx:142
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:200
long GetPrtRight(const SwFrame &rFrame) const
Definition: frame.hxx:1388
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:404
sal_uInt16 GetScalingOfSelectedText(TextFrameIndex nStt, TextFrameIndex nEnd)
Calculates the width of the text part specified by nStart and nEnd, the height of the line containing...
Definition: itratr.cxx:1219
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
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
long GetPrtLeft(const SwFrame &rFrame) const
Definition: frame.hxx:1387
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:62
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:78
void NewWord()
Definition: itratr.cxx:800
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:67
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:677
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
sal_uLong nMaxWidth
Definition: itratr.cxx:854
void Rst(SwTextAttr const *pHt)
Definition: itratr.cxx:110
OUString ExpandField(bool bCached, SwRootFrame const *pLayout) const
expand the field.
Definition: fldbas.cxx:404
LanguageType GetLanguage() const
Definition: swfont.hxx:282
#define CHAR_HARDHYPHEN
Definition: swtypes.hxx:173
#define RES_TXTATR_FIELD
Definition: hintids.hxx:151
void GetMinMaxSize(sal_uLong nIndex, sal_uLong &rMin, sal_uLong &rMax, sal_uLong &rAbs) const
Is in itratr.
Definition: itratr.cxx:990
#define RES_TXTATR_AUTOFMT
Definition: hintids.hxx:141
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
o3tl::enumarray< SwFontScript, const void * > m_aFontCacheIds
Definition: itratr.hxx:54
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:88
#define RES_DRAWFRMFMT
Definition: hintids.hxx:279
virtual const SwViewShell * GetCurrentViewShell() const =0
Returns the layout set at the document.
void SetFontCacheId(const void *nNewFontCacheId, const sal_uInt16 nIdx, SwFontScript nWhich)
Definition: swfont.hxx:199
vcl::Window * GetWin() const
Definition: viewsh.hxx:340
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:261
SwHTMLTableLayout * GetHTMLTableLayout()
Definition: swtable.hxx:174
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:154
SwAttrHandler m_aAttrHandler
Definition: itratr.hxx:37
void SetActual(SwFontScript nNew)
Definition: swfont.hxx:747
SwNodes & GetNodes()
Definition: doc.hxx:402
const SwPosition * End() const
Definition: pam.hxx:217
void Chg(SwTextAttr const *pHt)
Definition: itratr.cxx:100
VclPtr< OutputDevice > m_pLastOut
Definition: itratr.hxx:43
double getLength(const B2DPolygon &rCandidate)
sal_Int32 nNoLineBreak
Definition: itratr.cxx:795
#define RES_TXTATR_FLYCNT
Definition: hintids.hxx:152
#define RES_TXTATR_REFMARK
Definition: hintids.hxx:137
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:54
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:723
const SwFormatContent & GetContent(bool=true) const
Definition: fmtcntnt.hxx:55
long GetRight() const
void PushAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:340
const SwLineLayout * GetCurr() const
Definition: itrtxt.hxx:83
SwTextNode const * pLastNode
mainly for sanity checks
Definition: txtfrm.hxx:966
OutputDevice * get() const
SwFrameFormat * GetFrameFormat() const
Definition: fmtflcnt.hxx:45
sal_uLong & rMin
Definition: itratr.cxx:790
static sal_Int32 GetNextAttrImpl(SwTextNode const *pTextNode, size_t nStartIndex, size_t nEndIndex, sal_Int32 nPosition)
Definition: itratr.cxx:672
bool IsSymbol(TextFrameIndex nPos)
Definition: itratr.cxx:181
SwTextNode *const pFirstNode
except break attributes, those are taken from the first node
Definition: txtfrm.hxx:964
SwViewShell * m_pViewShell
Definition: itratr.hxx:38
#define RES_CHRATR_SCALEW
Definition: hintids.hxx:104
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:765
short m_nChgCnt
count currently open hints, redlines, ext-input
Definition: itratr.hxx:45
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:53
long GetTextLeft() const
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:204
virtual ~SwAttrIter()
Definition: itratr.cxx:121
sal_Int32 nPos
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
#define RES_TXTATR_INPUTFIELD
Definition: hintids.hxx:146
OUString m_Text
Definition: ndtxt.hxx:97
SdrObject * FindSdrObject()
Definition: frmfmt.hxx:137
sal_uLong nIndx
Definition: itratr.cxx:860
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
SwRootFrame * getRootFrame()
Definition: frame.hxx:657
static void InsertCharAttrs(SfxPoolItem const **pAttrs, SfxItemSet const &rItems)
Definition: itratr.cxx:438
const SfxPoolItem * GetCurItem() const
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
bool IsSymbolAt(TextFrameIndex) const
Definition: itratr.cxx:190
#define RES_CHRATR_RSID
Definition: hintids.hxx:108
const SwFormatFlyCnt & GetFlyCnt() const
Definition: txatbase.hxx:206
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74
Base class of the Writer document model elements.
Definition: node.hxx:79