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.FirstItem(); 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().get());
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().get());
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  if (aChar < CH_TXT_ATR_FORMELEMENT
711  || aChar > CH_TXT_ATR_FIELDEND)
712  {
713  ++p;
714  }
715  else
716  {
717  break;
718  }
719  }
720  assert(p <= nNext);
721  if (p < l)
722  {
723  // found a CH_TXT_ATR_FIELD*: if it's same as current position,
724  // skip behind it so that both before- and after-positions are returned
725  nNext = (nPosition < p) ? p : p + 1;
726  }
727  return nNext;
728 }
729 
731 {
732  size_t nStartIndex(m_nStartIndex);
733  size_t nEndIndex(m_nEndIndex);
734  size_t nPosition(m_nPosition);
735  SwTextNode const* pTextNode(m_pTextNode);
737 
738  while (true)
739  {
740  sal_Int32 nNext = GetNextAttrImpl(pTextNode, nStartIndex, nEndIndex, nPosition);
741  if( m_pRedline )
742  {
743  std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>> const redline(
744  m_pRedline->GetNextRedln(nNext, pTextNode, nActRedline));
745  if (redline.second.first)
746  {
747  assert(m_pMergedPara);
748  assert(redline.second.first->End()->nNode.GetIndex() <= m_pMergedPara->pLastNode->GetIndex()
749  || !redline.second.first->End()->nNode.GetNode().IsTextNode());
750  if (CanSkipOverRedline(*pTextNode, redline.first, *redline.second.first,
751  nStartIndex, nEndIndex, m_nPosition == redline.first))
752  { // if current position is start of the redline, must skip!
753  nActRedline += redline.second.second;
754  if (&redline.second.first->End()->nNode.GetNode() != pTextNode)
755  {
756  pTextNode = redline.second.first->End()->nNode.GetNode().GetTextNode();
757  nPosition = redline.second.first->End()->nContent.GetIndex();
758  }
759  else
760  {
761  nPosition = redline.second.first->End()->nContent.GetIndex();
762  }
763  }
764  else
765  {
766  return sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first);
767  }
768  }
769  else
770  {
771  return m_pMergedPara
772  ? sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first)
773  : TextFrameIndex(redline.first);
774  }
775  }
776  else
777  {
778  return TextFrameIndex(nNext);
779  }
780  }
781 }
782 
784 {
785 public:
787  SwViewShell const * pSh;
790  long nRowWidth;
792  long nWordAdd;
793  sal_Int32 nNoLineBreak;
794  SwMinMaxArgs( OutputDevice* pOutI, SwViewShell const * pShI, sal_uLong& rMinI, sal_uLong &rAbsI )
795  : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rAbsMin( rAbsI )
796  { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = COMPLETE_STRING; }
797  void Minimum( long nNew ) const { if( static_cast<long>(rMin) < nNew ) rMin = nNew; }
798  void NewWord() { nWordAdd = nWordWidth = 0; }
799 };
800 
801 static bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const OUString &rText,
802  sal_Int32 nIdx, sal_Int32 nEnd )
803 {
804  bool bRet = false;
805  while( nIdx < nEnd )
806  {
807  sal_Int32 nStop = nIdx;
808  LanguageType eLang = pFnt->GetLanguage();
809  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
810 
811  bool bClear = CH_BLANK == rText[ nStop ];
812  Boundary aBndry( g_pBreakIt->GetBreakIter()->getWordBoundary( rText, nIdx,
813  g_pBreakIt->GetLocale( eLang ),
814  WordType::DICTIONARY_WORD, true ) );
815  nStop = aBndry.endPos;
816  if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
817  rArg.NewWord();
818  if( nStop == nIdx )
819  ++nStop;
820  if( nStop > nEnd )
821  nStop = nEnd;
822 
823  SwDrawTextInfo aDrawInf(rArg.pSh, *rArg.pOut, rText, nIdx, nStop - nIdx);
824  long nCurrentWidth = pFnt->GetTextSize_( aDrawInf ).Width();
825  rArg.nRowWidth += nCurrentWidth;
826  if( bClear )
827  rArg.NewWord();
828  else
829  {
830  rArg.nWordWidth += nCurrentWidth;
831  if( static_cast<long>(rArg.rAbsMin) < rArg.nWordWidth )
832  rArg.rAbsMin = rArg.nWordWidth;
833  rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
834  bRet = true;
835  }
836  nIdx = nStop;
837  }
838  return bRet;
839 }
840 
841 bool SwTextNode::IsSymbolAt(const sal_Int32 nBegin) const
842 {
843  SwScriptInfo aScriptInfo;
844  SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
845  aIter.Seek( TextFrameIndex(nBegin) );
846  return aIter.GetFnt()->IsSymbol( getIDocumentLayoutAccess().GetCurrentViewShell() );
847 }
848 
850 {
851 public:
852  sal_uLong nMaxWidth; // sum of all frame widths
853  long nMinWidth; // biggest frame
854  long nLeftRest; // space not already covered by frames in the left margin
855  long nRightRest; // space not already covered by frames in the right margin
856  long nLeftDiff; // Min/Max-difference of the frame in the left margin
857  long nRightDiff; // Min/Max-difference of the frame in the right margin
858  sal_uLong nIndx; // index of the node
859  void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
860 };
861 
863 {
864  const SwFormatAnchor& rFormatA = pNd->GetAnchor();
865 
866  if ((RndStdIds::FLY_AT_PARA != rFormatA.GetAnchorId()) &&
867  (RndStdIds::FLY_AT_CHAR != rFormatA.GetAnchorId()))
868  {
869  return;
870  }
871 
872  const SwPosition *pPos = rFormatA.GetContentAnchor();
873  OSL_ENSURE(pPos && pIn, "Unexpected NULL arguments");
874  if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
875  return;
876 
877  long nMin, nMax;
878  SwHTMLTableLayout *pLayout = nullptr;
879  const bool bIsDrawFrameFormat = pNd->Which()==RES_DRAWFRMFMT;
880  if( !bIsDrawFrameFormat )
881  {
882  // Does the frame contain a table at the start or the end?
883  const SwNodes& rNodes = pNd->GetDoc()->GetNodes();
884  const SwFormatContent& rFlyContent = pNd->GetContent();
885  sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
886  SwTableNode* pTableNd = rNodes[nStt+1]->GetTableNode();
887  if( !pTableNd )
888  {
889  SwNode *pNd2 = rNodes[nStt];
890  pNd2 = rNodes[pNd2->EndOfSectionIndex()-1];
891  if( pNd2->IsEndNode() )
892  pTableNd = pNd2->StartOfSectionNode()->GetTableNode();
893  }
894 
895  if( pTableNd )
896  pLayout = pTableNd->GetTable().GetHTMLTableLayout();
897  }
898 
899  const SwFormatHoriOrient& rOrient = pNd->GetHoriOrient();
900  sal_Int16 eHoriOri = rOrient.GetHoriOrient();
901 
902  long nDiff;
903  if( pLayout )
904  {
905  nMin = pLayout->GetMin();
906  nMax = pLayout->GetMax();
907  nDiff = nMax - nMin;
908  }
909  else
910  {
911  if( bIsDrawFrameFormat )
912  {
913  const SdrObject* pSObj = pNd->FindSdrObject();
914  if( pSObj )
915  nMin = pSObj->GetCurrentBoundRect().GetWidth();
916  else
917  nMin = 0;
918 
919  }
920  else
921  {
922  const SwFormatFrameSize &rSz = pNd->GetFrameSize();
923  nMin = rSz.GetWidth();
924  }
925  nMax = nMin;
926  nDiff = 0;
927  }
928 
929  const SvxLRSpaceItem &rLR = pNd->GetLRSpace();
930  nMin += rLR.GetLeft();
931  nMin += rLR.GetRight();
932  nMax += rLR.GetLeft();
933  nMax += rLR.GetRight();
934 
935  if( css::text::WrapTextMode_THROUGH == pNd->GetSurround().GetSurround() )
936  {
937  pIn->Minimum( nMin );
938  return;
939  }
940 
941  // Frames, which are left- or right-aligned are only party considered
942  // when calculating the maximum, since the border is already being considered.
943  // Only if the frame extends into the text body, this part is being added
944  switch( eHoriOri )
945  {
947  {
948  if( nDiff )
949  {
950  pIn->nRightRest -= pIn->nRightDiff;
951  pIn->nRightDiff = nDiff;
952  }
953  if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
954  {
955  if( pIn->nRightRest > 0 )
956  pIn->nRightRest = 0;
957  }
958  pIn->nRightRest -= nMin;
959  break;
960  }
962  {
963  if( nDiff )
964  {
965  pIn->nLeftRest -= pIn->nLeftDiff;
966  pIn->nLeftDiff = nDiff;
967  }
968  if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
969  pIn->nLeftRest < 0 )
970  pIn->nLeftRest = 0;
971  pIn->nLeftRest -= nMin;
972  break;
973  }
974  default:
975  {
976  pIn->nMaxWidth += nMax;
977  pIn->Minimum( nMin );
978  }
979  }
980 }
981 
982 #define FLYINCNT_MIN_WIDTH 284
983 
989  sal_uLong& rAbsMin ) const
990 {
992  OutputDevice* pOut = nullptr;
993  if( pSh )
994  pOut = pSh->GetWin();
995  if( !pOut )
997 
998  MapMode aOldMap( pOut->GetMapMode() );
999  pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
1000 
1001  rMin = 0;
1002  rMax = 0;
1003  rAbsMin = 0;
1004 
1005  const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
1006  long nLROffset = rSpace.GetTextLeft() + GetLeftMarginWithNum( true );
1007  short nFLOffs;
1008  // For enumerations a negative first line indentation is probably filled already
1009  if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
1010  nLROffset = nFLOffs;
1011 
1012  SwMinMaxNodeArgs aNodeArgs;
1013  aNodeArgs.nMinWidth = 0;
1014  aNodeArgs.nMaxWidth = 0;
1015  aNodeArgs.nLeftRest = nLROffset;
1016  aNodeArgs.nRightRest = rSpace.GetRight();
1017  aNodeArgs.nLeftDiff = 0;
1018  aNodeArgs.nRightDiff = 0;
1019  if( nIndex )
1020  {
1021  SwFrameFormats* pTmp = const_cast<SwFrameFormats*>(GetDoc()->GetSpzFrameFormats());
1022  if( pTmp )
1023  {
1024  aNodeArgs.nIndx = nIndex;
1025  for( SwFrameFormat *pFormat : *pTmp )
1026  lcl_MinMaxNode( pFormat, &aNodeArgs );
1027  }
1028  }
1029  if( aNodeArgs.nLeftRest < 0 )
1030  aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
1031  aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
1032  if( aNodeArgs.nLeftRest < 0 )
1033  aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
1034 
1035  if( aNodeArgs.nRightRest < 0 )
1036  aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
1037  aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
1038  if( aNodeArgs.nRightRest < 0 )
1039  aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
1040 
1041  SwScriptInfo aScriptInfo;
1042  SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
1043  TextFrameIndex nIdx(0);
1044  aIter.SeekAndChgAttrIter( nIdx, pOut );
1045  TextFrameIndex nLen(m_Text.getLength());
1046  long nCurrentWidth = 0;
1047  long nAdd = 0;
1048  SwMinMaxArgs aArg( pOut, pSh, rMin, rAbsMin );
1049  while( nIdx < nLen )
1050  {
1051  TextFrameIndex nNextChg = aIter.GetNextAttr();
1052  TextFrameIndex nStop = aScriptInfo.NextScriptChg( nIdx );
1053  if( nNextChg > nStop )
1054  nNextChg = nStop;
1055  SwTextAttr *pHint = nullptr;
1056  sal_Unicode cChar = CH_BLANK;
1057  nStop = nIdx;
1058  while( nStop < nLen && nStop < nNextChg &&
1059  CH_TAB != (cChar = m_Text[sal_Int32(nStop)]) &&
1060  CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
1061  CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
1062  !pHint )
1063  {
1064  if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
1065  || ( nullptr == ( pHint = aIter.GetAttr( nStop ) ) ) )
1066  ++nStop;
1067  }
1068  if (lcl_MinMaxString(aArg, aIter.GetFnt(), m_Text, sal_Int32(nIdx), sal_Int32(nStop)))
1069  {
1070  nAdd = 20;
1071  }
1072  nIdx = nStop;
1073  aIter.SeekAndChgAttrIter( nIdx, pOut );
1074  switch( cChar )
1075  {
1076  case CH_BREAK :
1077  {
1078  if( static_cast<long>(rMax) < aArg.nRowWidth )
1079  rMax = aArg.nRowWidth;
1080  aArg.nRowWidth = 0;
1081  aArg.NewWord();
1082  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1083  }
1084  break;
1085  case CH_TAB :
1086  {
1087  aArg.NewWord();
1088  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1089  }
1090  break;
1091  case CHAR_SOFTHYPHEN:
1092  ++nIdx;
1093  break;
1094  case CHAR_HARDBLANK:
1095  case CHAR_HARDHYPHEN:
1096  {
1097  OUString sTmp( cChar );
1098  SwDrawTextInfo aDrawInf( pSh,
1099  *pOut, sTmp, 0, 1, 0, false );
1100  nCurrentWidth = aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1101  aArg.nWordWidth += nCurrentWidth;
1102  aArg.nRowWidth += nCurrentWidth;
1103  if( static_cast<long>(rAbsMin) < aArg.nWordWidth )
1104  rAbsMin = aArg.nWordWidth;
1105  aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
1106  aArg.nNoLineBreak = sal_Int32(nIdx++);
1107  }
1108  break;
1109  case CH_TXTATR_BREAKWORD:
1110  case CH_TXTATR_INWORD:
1111  {
1112  if( !pHint )
1113  break;
1114  long nOldWidth = aArg.nWordWidth;
1115  long nOldAdd = aArg.nWordAdd;
1116  aArg.NewWord();
1117 
1118  switch( pHint->Which() )
1119  {
1120  case RES_TXTATR_FLYCNT :
1121  {
1122  SwFrameFormat *pFrameFormat = pHint->GetFlyCnt().GetFrameFormat();
1123  const SvxLRSpaceItem &rLR = pFrameFormat->GetLRSpace();
1124  if( RES_DRAWFRMFMT == pFrameFormat->Which() )
1125  {
1126  const SdrObject* pSObj = pFrameFormat->FindSdrObject();
1127  if( pSObj )
1128  nCurrentWidth = pSObj->GetCurrentBoundRect().GetWidth();
1129  else
1130  nCurrentWidth = 0;
1131  }
1132  else
1133  {
1134  const SwFormatFrameSize& rTmpSize = pFrameFormat->GetFrameSize();
1135  if( RES_FLYFRMFMT == pFrameFormat->Which()
1136  && rTmpSize.GetWidthPercent() )
1137  {
1138  // This is a hack for the following situation: In the paragraph there's a
1139  // text frame with relative size. Then let's take 0.5 cm as minimum width
1140  // and USHRT_MAX as maximum width
1141  // It were cleaner and maybe necessary later on to iterate over the content
1142  // of the text frame and call GetMinMaxSize recursively
1143  nCurrentWidth = FLYINCNT_MIN_WIDTH; // 0.5 cm
1144  rMax = std::max(rMax, sal_uLong(USHRT_MAX));
1145  }
1146  else
1147  nCurrentWidth = pFrameFormat->GetFrameSize().GetWidth();
1148  }
1149  nCurrentWidth += rLR.GetLeft();
1150  nCurrentWidth += rLR.GetRight();
1151  aArg.nWordAdd = nOldWidth + nOldAdd;
1152  aArg.nWordWidth = nCurrentWidth;
1153  aArg.nRowWidth += nCurrentWidth;
1154  if( static_cast<long>(rAbsMin) < aArg.nWordWidth )
1155  rAbsMin = aArg.nWordWidth;
1156  aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
1157  break;
1158  }
1159  case RES_TXTATR_FTN :
1160  {
1161  const OUString aText = pHint->GetFootnote().GetNumStr();
1162  if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
1163  aText.getLength() ) )
1164  nAdd = 20;
1165  break;
1166  }
1167 
1168  case RES_TXTATR_FIELD :
1169  case RES_TXTATR_ANNOTATION :
1170  {
1171  SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
1172  const OUString aText = pField->ExpandField(true, nullptr);
1173  if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
1174  aText.getLength() ) )
1175  nAdd = 20;
1176  break;
1177  }
1178  default: aArg.nWordWidth = nOldWidth;
1179  aArg.nWordAdd = nOldAdd;
1180 
1181  }
1182  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1183  }
1184  break;
1185  }
1186  }
1187  if( static_cast<long>(rMax) < aArg.nRowWidth )
1188  rMax = aArg.nRowWidth;
1189 
1190  nLROffset += rSpace.GetRight();
1191 
1192  rAbsMin += nLROffset;
1193  rAbsMin += nAdd;
1194  rMin += nLROffset;
1195  rMin += nAdd;
1196  if( static_cast<long>(rMin) < aNodeArgs.nMinWidth )
1197  rMin = aNodeArgs.nMinWidth;
1198  if( static_cast<long>(rAbsMin) < aNodeArgs.nMinWidth )
1199  rAbsMin = aNodeArgs.nMinWidth;
1200  rMax += aNodeArgs.nMaxWidth;
1201  rMax += nLROffset;
1202  rMax += nAdd;
1203  if( rMax < rMin ) // e.g. Frames with flow through only contribute to the minimum
1204  rMax = rMin;
1205  pOut->SetMapMode( aOldMap );
1206 }
1207 
1218  TextFrameIndex nStart, TextFrameIndex nEnd)
1219 {
1220  assert(GetOfst() <= nStart && (!GetFollow() || nStart < GetFollow()->GetOfst()));
1221  SwViewShell const*const pSh = getRootFrame()->GetCurrShell();
1222  assert(pSh);
1223  OutputDevice *const pOut = &pSh->GetRefDev();
1224  assert(pOut);
1225 
1226  MapMode aOldMap( pOut->GetMapMode() );
1227  pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
1228 
1229  if (nStart == nEnd)
1230  {
1231  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
1232 
1233  SwScriptInfo aScriptInfo;
1234  SwAttrIter aIter(*GetTextNodeFirst(), aScriptInfo, this);
1235  aIter.SeekAndChgAttrIter( nStart, pOut );
1236 
1237  Boundary aBound = g_pBreakIt->GetBreakIter()->getWordBoundary(
1238  GetText(), sal_Int32(nStart),
1239  g_pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
1240  WordType::DICTIONARY_WORD, true );
1241 
1242  if (sal_Int32(nStart) == aBound.startPos)
1243  {
1244  // cursor is at left or right border of word
1245  pOut->SetMapMode( aOldMap );
1246  return 100;
1247  }
1248 
1249  nStart = TextFrameIndex(aBound.startPos);
1250  nEnd = TextFrameIndex(aBound.endPos);
1251 
1252  if (nStart == nEnd)
1253  {
1254  pOut->SetMapMode( aOldMap );
1255  return 100;
1256  }
1257  }
1258 
1259  SwScriptInfo aScriptInfo;
1260  SwAttrIter aIter(*GetTextNodeFirst(), aScriptInfo, this);
1261 
1262  // We do not want scaling attributes to be considered during this
1263  // calculation. For this, we push a temporary scaling attribute with
1264  // scaling value 100 and priority flag on top of the scaling stack
1265  SwAttrHandler& rAH = aIter.GetAttrHandler();
1267  SwTextAttrEnd aAttr( aItem, 0, COMPLETE_STRING );
1268  aAttr.SetPriorityAttr( true );
1269  rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
1270 
1271  TextFrameIndex nIdx = nStart;
1272 
1273  sal_uLong nWidth = 0;
1274  sal_uLong nProWidth = 0;
1275 
1276  while( nIdx < nEnd )
1277  {
1278  aIter.SeekAndChgAttrIter( nIdx, pOut );
1279 
1280  // scan for end of portion
1281  TextFrameIndex const nNextChg = std::min(aIter.GetNextAttr(), aScriptInfo.NextScriptChg(nIdx));
1282 
1283  TextFrameIndex nStop = nIdx;
1284  sal_Unicode cChar = CH_BLANK;
1285  SwTextAttr* pHint = nullptr;
1286 
1287  // stop at special characters in [ nIdx, nNextChg ]
1288  while( nStop < nEnd && nStop < nNextChg )
1289  {
1290  cChar = GetText()[sal_Int32(nStop)];
1291  if (
1292  CH_TAB == cChar ||
1293  CH_BREAK == cChar ||
1294  CHAR_HARDBLANK == cChar ||
1295  CHAR_HARDHYPHEN == cChar ||
1296  CHAR_SOFTHYPHEN == cChar ||
1297  (
1298  (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
1299  (nullptr == (pHint = aIter.GetAttr(nStop)))
1300  )
1301  )
1302  {
1303  break;
1304  }
1305  else
1306  ++nStop;
1307  }
1308 
1309  // calculate text widths up to cChar
1310  if ( nStop > nIdx )
1311  {
1312  SwDrawTextInfo aDrawInf(pSh, *pOut, GetText(), sal_Int32(nIdx), sal_Int32(nStop - nIdx));
1313  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1314  }
1315 
1316  nIdx = nStop;
1317  aIter.SeekAndChgAttrIter( nIdx, pOut );
1318 
1319  if ( cChar == CH_BREAK )
1320  {
1321  nWidth = std::max( nWidth, nProWidth );
1322  nProWidth = 0;
1323  nIdx++;
1324  }
1325  else if ( cChar == CH_TAB )
1326  {
1327  // tab receives width of one space
1328  OUString sTmp( CH_BLANK );
1329  SwDrawTextInfo aDrawInf(pSh, *pOut, sTmp, 0, 1);
1330  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1331  nIdx++;
1332  }
1333  else if ( cChar == CHAR_SOFTHYPHEN )
1334  ++nIdx;
1335  else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
1336  {
1337  OUString sTmp( cChar );
1338  SwDrawTextInfo aDrawInf(pSh, *pOut, sTmp, 0, 1);
1339  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1340  nIdx++;
1341  }
1342  else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || cChar == CH_TXTATR_INWORD ) )
1343  {
1344  switch( pHint->Which() )
1345  {
1346  case RES_TXTATR_FTN :
1347  {
1348  const OUString aText = pHint->GetFootnote().GetNumStr();
1349  SwDrawTextInfo aDrawInf(pSh, *pOut, aText, 0, aText.getLength());
1350 
1351  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1352  break;
1353  }
1354 
1355  case RES_TXTATR_FIELD :
1356  case RES_TXTATR_ANNOTATION :
1357  {
1358  SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
1359  OUString const aText = pField->ExpandField(true, getRootFrame());
1360  SwDrawTextInfo aDrawInf(pSh, *pOut, aText, 0, aText.getLength());
1361 
1362  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1363  break;
1364  }
1365 
1366  default:
1367  {
1368  // any suggestions for a default action?
1369  }
1370  } // end of switch
1371  nIdx++;
1372  } // end of while
1373  }
1374 
1375  nWidth = std::max( nWidth, nProWidth );
1376 
1377  // search for the line containing nStart
1378  if (HasPara())
1379  {
1380  SwTextInfo aInf(this);
1381  SwTextIter aLine(this, &aInf);
1382  aLine.CharToLine( nStart );
1383  pOut->SetMapMode( aOldMap );
1384  return static_cast<sal_uInt16>( nWidth ?
1385  ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1386  }
1387  // no frame or no paragraph, we take the height of the character
1388  // at nStart as line height
1389 
1390  aIter.SeekAndChgAttrIter( nStart, pOut );
1391  pOut->SetMapMode( aOldMap );
1392 
1393  SwDrawTextInfo aDrawInf(pSh, *pOut, GetText(), sal_Int32(nStart), 1);
1394  return static_cast<sal_uInt16>( nWidth ? ((100 * aIter.GetFnt()->GetTextSize_( aDrawInf ).Height()) / nWidth ) : 0 );
1395 }
1396 
1398 {
1399  SwTwips nRet = 0;
1400 
1401  sal_Int32 nIdx = 0;
1402 
1403  while ( nIdx < GetText().getLength() )
1404  {
1405  const sal_Unicode cCh = GetText()[nIdx];
1406  if ( cCh!='\t' && cCh!=' ' )
1407  {
1408  break;
1409  }
1410  ++nIdx;
1411  }
1412 
1413  if ( nIdx > 0 )
1414  {
1415  SwPosition aPos( *this );
1416  aPos.nContent += nIdx;
1417 
1418  // Find the non-follow text frame:
1420  for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1421  {
1422  // Only consider master frames:
1423  if (!pFrame->IsFollow() &&
1424  pFrame->GetTextNodeForFirstText() == this)
1425  {
1426  SwRectFnSet aRectFnSet(pFrame);
1427  SwRect aRect;
1428  pFrame->GetCharRect( aRect, aPos );
1429  nRet = pFrame->IsRightToLeft() ?
1430  aRectFnSet.GetPrtRight(*pFrame) - aRectFnSet.GetRight(aRect) :
1431  aRectFnSet.GetLeft(aRect) - aRectFnSet.GetPrtLeft(*pFrame);
1432  break;
1433  }
1434  }
1435  }
1436 
1437  return nRet;
1438 }
1439 
1440 /* 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:787
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:71
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:342
sal_uInt16 Height() const
Definition: possiz.hxx:44
#define RES_TXTATR_CJK_RUBY
Definition: hintids.hxx:143
const OUString & GetText() const
Definition: ndtxt.hxx:211
void PopAndChg(const SwTextAttr &rAttr, SwFont &rFnt)
Definition: atrstck.cxx:428
SwTextAttr * GetAttr(TextFrameIndex nPos) const
Returns the attribute for a position.
Definition: itratr.cxx:147
#define RES_TXTATR_METAFIELD
Definition: hintids.hxx:139
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:219
#define FLYINCNT_MIN_WIDTH
Definition: itratr.cxx:982
bool HasPara() const
Definition: txtfrm.hxx:808
long nWordAdd
Definition: itratr.cxx:792
static bool lcl_MinMaxString(SwMinMaxArgs &rArg, SwFont *pFnt, const OUString &rText, sal_Int32 nIdx, sal_Int32 nEnd)
Definition: itratr.cxx:801
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:279
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:376
#define RES_TXTATR_UNKNOWN_CONTAINER
Definition: hintids.hxx:144
TextFrameIndex GetOfst() const
Definition: txtfrm.hxx:426
#define CHAR_HARDBLANK
Definition: swtypes.hxx:172
const MapMode & GetMapMode() const
TextFrameIndex GetNextAttr() const
Definition: itratr.cxx:730
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:1397
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:142
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 SfxPoolItem * FirstItem()
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:841
#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:138
sal_uInt16 sal_Unicode
#define RES_CHRATR_END
Definition: hintids.hxx:114
#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:794
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:151
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:70
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:2076
bool IsFntChg() const
Definition: swfont.hxx:207
#define SAL_N_ELEMENTS(arr)
void Minimum(long nNew) const
Definition: itratr.cxx:797
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:274
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:337
void Minimum(long nNew)
Definition: itratr.cxx:859
sal_uLong & rAbsMin
Definition: itratr.cxx:789
long nWordWidth
Definition: itratr.cxx:791
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:152
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:790
VclPtr< OutputDevice > pOut
Definition: itratr.cxx:786
Count
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1182
TElementType * First()
Definition: calbck.hxx:345
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
const SfxPoolItem * NextItem()
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(MergedPara const &, TextFrameIndex nIndex)
Definition: txtfrm.cxx:1163
SwDoc * GetDoc()
Definition: node.hxx:702
#define RES_CHRATR_BEGIN
Definition: hintids.hxx:68
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:137
bool IsEndNode() const
Definition: node.hxx:632
static void lcl_MinMaxNode(SwFrameFormat *pNd, SwMinMaxNodeArgs *pIn)
Definition: itratr.cxx:862
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:141
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:437
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:1217
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:2058
long GetPrtLeft(const SwFrame &rFrame) const
Definition: frame.hxx:1387
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:78
void NewWord()
Definition: itratr.cxx:798
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:852
void Rst(SwTextAttr const *pHt)
Definition: itratr.cxx:110
OUString ExpandField(bool bCached, SwRootFrame const *pLayout) const
expand the field.
Definition: fldbas.cxx:412
LanguageType GetLanguage() const
Definition: swfont.hxx:282
#define CHAR_HARDHYPHEN
Definition: swtypes.hxx:173
#define RES_TXTATR_FIELD
Definition: hintids.hxx:150
void GetMinMaxSize(sal_uLong nIndex, sal_uLong &rMin, sal_uLong &rMax, sal_uLong &rAbs) const
Is in itratr.
Definition: itratr.cxx:988
#define RES_TXTATR_AUTOFMT
Definition: hintids.hxx:140
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:277
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:153
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:793
#define RES_TXTATR_FLYCNT
Definition: hintids.hxx:151
#define RES_TXTATR_REFMARK
Definition: hintids.hxx:136
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:53
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:343
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter()
Definition: breakit.hxx:62
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:788
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:103
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:765
short m_nChgCnt
count currently open hints, redlines, ext-input
Definition: itratr.hxx:45
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:145
OUString m_Text
Definition: ndtxt.hxx:98
SdrObject * FindSdrObject()
Definition: frmfmt.hxx:137
sal_uLong nIndx
Definition: itratr.cxx:858
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
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:843
bool IsSymbolAt(TextFrameIndex) const
Definition: itratr.cxx:190
#define RES_CHRATR_RSID
Definition: hintids.hxx:107
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