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 a 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:
343  m_pMergedPara->mergedText, nullptr, nullptr);
344  // reset to next
345  m_pTextNode = newPos.first;
346  m_nStartIndex = 0;
347  m_nEndIndex = 0;
348  m_nPosition = 0;
349  assert(m_pRedline);
350  }
351 
352  // sw_redlinehide: Seek(0) must move before the first character, which
353  // has a special case where the first node starts with delete redline.
354  if ((!nNewPos && !m_pMergedPara)
355  || newPos.first != m_pTextNode
356  || newPos.second < m_nPosition)
357  {
358  if (m_pMergedPara)
359  {
360  if (m_pTextNode != newPos.first)
361  {
362  m_pTextNode = newPos.first;
363  // sw_redlinehide: hope it's okay to use the current text node
364  // here; the AttrHandler shouldn't care about non-char items
366  m_pMergedPara->mergedText, nullptr, nullptr);
367  }
368  }
370  {
371  if( m_pRedline )
372  m_pRedline->Clear( nullptr );
373 
374  // reset font to its original state
377 
378  if( m_nPropFont )
380  m_nStartIndex = 0;
381  m_nEndIndex = 0;
382  m_nPosition = 0;
383  m_nChgCnt = 0;
384 
385  // Attention!
386  // resetting the font here makes it necessary to apply any
387  // changes for extended input directly to the font
388  if ( m_pRedline && m_pRedline->ExtOn() )
389  {
390  m_pRedline->UpdateExtFont( *m_pFont );
391  ++m_nChgCnt;
392  }
393  }
394  }
395 
396  if (m_pTextNode->GetpSwpHints())
397  {
398  if (m_pMergedPara)
399  {
400  // iterate hint by hint: SeekFwd does not mix ends and starts,
401  // it always applies all the starts last, so it must be called once
402  // per position where hints start/end!
403  sal_Int32 nPos(m_nPosition);
404  do
405  {
406  sal_Int32 const nOldPos(nPos);
408  if (nPos <= newPos.second)
409  {
410  SeekFwd(nOldPos, nPos);
411  }
412  else
413  {
414  SeekFwd(nOldPos, newPos.second);
415  }
416  }
417  while (nPos < newPos.second);
418  }
419  else
420  {
421  SeekFwd(m_nPosition, newPos.second);
422  }
423  }
424 
426 
427  if( m_pRedline )
428  m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, m_pTextNode->GetIndex(), newPos.second, m_nPosition);
429  m_nPosition = newPos.second;
430 
431  if( m_nPropFont )
433 
434  return m_pFont->IsFntChg();
435 }
436 
437 static void InsertCharAttrs(SfxPoolItem const** pAttrs, SfxItemSet const& rItems)
438 {
439  SfxItemIter iter(rItems);
440  for (SfxPoolItem const* pItem = iter.FirstItem(); pItem; pItem = iter.NextItem())
441  {
442  auto const nWhich(pItem->Which());
443  if (isCHRATR(nWhich) && RES_CHRATR_RSID != nWhich)
444  {
445  pAttrs[nWhich - RES_CHRATR_BEGIN] = pItem;
446  }
447  else if (nWhich == RES_TXTATR_UNKNOWN_CONTAINER)
448  {
449  pAttrs[RES_CHRATR_END] = pItem;
450  }
451  }
452 }
453 
454 // if return false: portion ends at start of redline, indexes unchanged
455 // if return true: portion end not known (past end of redline), indexes point to first hint past end of redline
456 static bool CanSkipOverRedline(
457  SwTextNode const& rStartNode, sal_Int32 const nStartRedline,
458  SwRangeRedline const& rRedline,
459  size_t & rStartIndex, size_t & rEndIndex,
460  bool const isTheAnswerYes)
461 {
462  size_t nStartIndex(rStartIndex);
463  size_t nEndIndex(rEndIndex);
464  SwPosition const*const pRLEnd(rRedline.End());
465  if (!pRLEnd->nNode.GetNode().IsTextNode() // if fully deleted...
466  || pRLEnd->nContent == pRLEnd->nNode.GetNode().GetTextNode()->Len())
467  {
468  // shortcut: nothing follows redline
469  // current state is end state
470  return false;
471  }
472  std::vector<SwTextAttr*> activeCharFmts;
473  // can't compare the SwFont that's stored somewhere, it doesn't have compare
474  // operator, so try to recreate the situation with some temp arrays here
475  SfxPoolItem const* activeCharAttrsStart[RES_CHRATR_END - RES_CHRATR_BEGIN + 1] = { nullptr, };
476  if (&rStartNode != &pRLEnd->nNode.GetNode())
477  { // nodes' attributes are only needed if there are different nodes
478  InsertCharAttrs(activeCharAttrsStart, rStartNode.GetSwAttrSet());
479  }
480  if (SwpHints const*const pStartHints = rStartNode.GetpSwpHints())
481  {
482  // check hint ends of hints that start before and end within
483  sal_Int32 const nRedlineEnd(&rStartNode == &pRLEnd->nNode.GetNode()
484  ? pRLEnd->nContent.GetIndex()
485  : rStartNode.Len());
486  for ( ; nEndIndex < pStartHints->Count(); ++nEndIndex)
487  {
488  SwTextAttr *const pAttr(pStartHints->GetSortedByEnd(nEndIndex));
489  if (!pAttr->End())
490  {
491  continue;
492  }
493  if (nRedlineEnd < *pAttr->End())
494  {
495  break;
496  }
497  if (nStartRedline <= pAttr->GetStart())
498  {
499  continue;
500  }
501  if (pAttr->IsFormatIgnoreEnd())
502  {
503  continue;
504  }
505  switch (pAttr->Which())
506  {
507  // if any of these ends inside RL then we need a new portion
508  case RES_TXTATR_REFMARK:
509  case RES_TXTATR_TOXMARK:
510  case RES_TXTATR_META: // actually these 2 aren't allowed to overlap ???
512  case RES_TXTATR_INETFMT:
513  case RES_TXTATR_CJK_RUBY:
515  {
516  if (!isTheAnswerYes) return false; // always break
517  }
518  break;
519  // these are guaranteed not to overlap
520  // and come in order of application
521  case RES_TXTATR_AUTOFMT:
522  case RES_TXTATR_CHARFMT:
523  {
524  if (pAttr->Which() == RES_TXTATR_CHARFMT)
525  {
526  activeCharFmts.push_back(pAttr);
527  }
528  // pure formatting hints may end inside the redline &
529  // start again inside the redline, which must not cause
530  // a new text portion if they have the same items - so
531  // store the effective items & compare all at the end
532  SfxItemSet const& rSet((pAttr->Which() == RES_TXTATR_CHARFMT)
533  ? static_cast<SfxItemSet const&>(pAttr->GetCharFormat().GetCharFormat()->GetAttrSet())
534  : *pAttr->GetAutoFormat().GetStyleHandle().get());
535  InsertCharAttrs(activeCharAttrsStart, rSet);
536  }
537  break;
538  // SwTextNode::SetAttr puts it into AUTOFMT which is quite
539  // sensible so it doesn't actually exist as a hint
541  default: assert(false);
542  }
543  }
544  assert(nEndIndex == pStartHints->Count() ||
545  pRLEnd->nContent.GetIndex() < *pStartHints->GetSortedByEnd(nEndIndex)->GetAnyEnd());
546  }
547 
548  if (&rStartNode != &pRLEnd->nNode.GetNode())
549  {
550  nStartIndex = 0;
551  nEndIndex = 0;
552  }
553 
554  // treat para properties as text properties
555  // ... with the FormatToTextAttr we get autofmts that correspond to the *effective* attr set difference
556  // effective attr set: para props + charfmts + autofmt *in that order*
557  // ... and the charfmt must be *nominally* the same
558 
559  SfxPoolItem const* activeCharAttrsEnd[RES_CHRATR_END - RES_CHRATR_BEGIN + 1] = { nullptr, };
560  if (&rStartNode != &pRLEnd->nNode.GetNode())
561  { // nodes' attributes are only needed if there are different nodes
562  InsertCharAttrs(activeCharAttrsEnd,
563  pRLEnd->nNode.GetNode().GetTextNode()->GetSwAttrSet());
564  }
565 
566  if (SwpHints *const pEndHints = pRLEnd->nNode.GetNode().GetTextNode()->GetpSwpHints())
567  {
568  // check hint starts of hints that start within and end after
569 #ifndef NDEBUG
570  sal_Int32 const nRedlineStart(&rStartNode == &pRLEnd->nNode.GetNode()
571  ? nStartRedline
572  : 0);
573 #endif
574  for ( ; nStartIndex < pEndHints->Count(); ++nStartIndex)
575  {
576  SwTextAttr *const pAttr(pEndHints->Get(nStartIndex));
577  // compare with < here, not <=, to get the effective formatting
578  // of the 1st char after the redline; should not cause problems
579  // with consecutive delete redlines because those are handed by
580  // GetNextRedln() and here we have the last end pos.
581  if (pRLEnd->nContent.GetIndex() < pAttr->GetStart())
582  {
583  break;
584  }
585  if (!pAttr->End())
586  continue;
587  if (pAttr->IsFormatIgnoreStart())
588  {
589  continue;
590  }
591  assert(nRedlineStart <= pAttr->GetStart()); // we wouldn't be here otherwise?
592  if (*pAttr->End() <= pRLEnd->nContent.GetIndex())
593  {
594  continue;
595  }
596  switch (pAttr->Which())
597  {
598  case RES_TXTATR_REFMARK:
599  case RES_TXTATR_TOXMARK:
600  case RES_TXTATR_META: // actually these 2 aren't allowed to overlap ???
602  case RES_TXTATR_INETFMT:
603  case RES_TXTATR_CJK_RUBY:
605  {
606  if (!isTheAnswerYes) return false;
607  }
608  break;
609  case RES_TXTATR_AUTOFMT:
610  case RES_TXTATR_CHARFMT:
611  {
612  // char formats must be *nominally* the same
613  if (pAttr->Which() == RES_TXTATR_CHARFMT)
614  {
615  auto iter = std::find_if(activeCharFmts.begin(), activeCharFmts.end(),
616  [&pAttr](const SwTextAttr* pCharFmt) { return *pCharFmt == *pAttr; });
617  if (iter != activeCharFmts.end())
618  activeCharFmts.erase(iter);
619  else if (!isTheAnswerYes)
620  return false;
621  }
622  SfxItemSet const& rSet((pAttr->Which() == RES_TXTATR_CHARFMT)
623  ? static_cast<SfxItemSet const&>(pAttr->GetCharFormat().GetCharFormat()->GetAttrSet())
624  : *pAttr->GetAutoFormat().GetStyleHandle().get());
625  InsertCharAttrs(activeCharAttrsEnd, rSet);
626 
627  }
628  break;
629  // SwTextNode::SetAttr puts it into AUTOFMT which is quite
630  // sensible so it doesn't actually exist as a hint
632  default: assert(false);
633  }
634  }
635  if (&rStartNode != &pRLEnd->nNode.GetNode())
636  {
637  // need to iterate the nEndIndex forward too so the loop in the
638  // caller can look for the right ends in the next iteration
639  for (nEndIndex = 0; nEndIndex < pEndHints->Count(); ++nEndIndex)
640  {
641  SwTextAttr *const pAttr(pEndHints->GetSortedByEnd(nEndIndex));
642  if (!pAttr->End())
643  continue;
644  if (pRLEnd->nContent.GetIndex() < *pAttr->End())
645  {
646  break;
647  }
648  }
649  }
650  }
651 
652  // if we didn't find a matching start for any end, then it really ends inside
653  if (!activeCharFmts.empty())
654  {
655  if (!isTheAnswerYes) return false;
656  }
657  for (size_t i = 0; i < SAL_N_ELEMENTS(activeCharAttrsStart); ++i)
658  {
659  // all of these are poolable
660 // assert(!activeCharAttrsStart[i] || activeCharAttrsStart[i]->GetItemPool()->IsItemPoolable(*activeCharAttrsStart[i]));
661  if (activeCharAttrsStart[i] != activeCharAttrsEnd[i])
662  {
663  if (!isTheAnswerYes) return false;
664  }
665  }
666  rStartIndex = nStartIndex;
667  rEndIndex = nEndIndex;
668  return true;
669 }
670 
671 static sal_Int32 GetNextAttrImpl(SwTextNode const*const pTextNode,
672  size_t const nStartIndex, size_t const nEndIndex,
673  sal_Int32 const nPosition)
674 {
675  // note: this used to be COMPLETE_STRING, but was set to Len() + 1 below,
676  // which is rather silly, so set it to Len() instead
677  sal_Int32 nNext = pTextNode->Len();
678  if (SwpHints const*const pHints = pTextNode->GetpSwpHints())
679  {
680  // are there attribute starts left?
681  for (size_t i = nStartIndex; i < pHints->Count(); ++i)
682  {
683  SwTextAttr *const pAttr(pHints->Get(i));
684  if (!pAttr->IsFormatIgnoreStart())
685  {
686  nNext = pAttr->GetStart();
687  break;
688  }
689  }
690  // are there attribute ends left?
691  for (size_t i = nEndIndex; i < pHints->Count(); ++i)
692  {
693  SwTextAttr *const pAttr(pHints->GetSortedByEnd(i));
694  if (!pAttr->IsFormatIgnoreEnd())
695  {
696  sal_Int32 const nNextEnd = *pAttr->GetAnyEnd();
697  nNext = std::min(nNext, nNextEnd); // pick nearest one
698  break;
699  }
700  }
701  }
702  // TODO: maybe use hints like FieldHints for this instead of looking at the text...
703  const sal_Int32 l = std::min(nNext, pTextNode->Len());
704  sal_Int32 p = nPosition;
705  const sal_Unicode* pStr = pTextNode->GetText().getStr();
706  while (p < l)
707  {
708  sal_Unicode aChar = pStr[p];
709  if (aChar < CH_TXT_ATR_FORMELEMENT
710  || aChar > CH_TXT_ATR_FIELDEND)
711  {
712  ++p;
713  }
714  else
715  {
716  break;
717  }
718  }
719  assert(p <= nNext);
720  if (p < l)
721  {
722  // found a CH_TXT_ATR_FIELD*: if it's same as current position,
723  // skip behind it so that both before- and after-positions are returned
724  nNext = (nPosition < p) ? p : p + 1;
725  }
726  return nNext;
727 }
728 
730 {
731  size_t nStartIndex(m_nStartIndex);
732  size_t nEndIndex(m_nEndIndex);
733  size_t nPosition(m_nPosition);
734  SwTextNode const* pTextNode(m_pTextNode);
736 
737  while (true)
738  {
739  sal_Int32 nNext = GetNextAttrImpl(pTextNode, nStartIndex, nEndIndex, nPosition);
740  if( m_pRedline )
741  {
742  std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>> const redline(
743  m_pRedline->GetNextRedln(nNext, pTextNode, nActRedline));
744  if (redline.second.first)
745  {
746  assert(m_pMergedPara);
747  assert(redline.second.first->End()->nNode.GetIndex() <= m_pMergedPara->pLastNode->GetIndex()
748  || !redline.second.first->End()->nNode.GetNode().IsTextNode());
749  if (CanSkipOverRedline(*pTextNode, redline.first, *redline.second.first,
750  nStartIndex, nEndIndex, m_nPosition == redline.first))
751  { // if current position is start of the redline, must skip!
752  nActRedline += redline.second.second;
753  if (&redline.second.first->End()->nNode.GetNode() != pTextNode)
754  {
755  pTextNode = redline.second.first->End()->nNode.GetNode().GetTextNode();
756  nPosition = redline.second.first->End()->nContent.GetIndex();
757  }
758  else
759  {
760  nPosition = redline.second.first->End()->nContent.GetIndex();
761  }
762  }
763  else
764  {
765  return sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first);
766  }
767  }
768  else
769  {
770  return m_pMergedPara
771  ? sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first)
772  : TextFrameIndex(redline.first);
773  }
774  }
775  else
776  {
777  return TextFrameIndex(nNext);
778  }
779  }
780 }
781 
783 {
784 public:
786  SwViewShell const * pSh;
789  long nRowWidth;
791  long nWordAdd;
792  sal_Int32 nNoLineBreak;
793  SwMinMaxArgs( OutputDevice* pOutI, SwViewShell const * pShI, sal_uLong& rMinI, sal_uLong &rAbsI )
794  : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rAbsMin( rAbsI )
795  { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = COMPLETE_STRING; }
796  void Minimum( long nNew ) const { if( static_cast<long>(rMin) < nNew ) rMin = nNew; }
797  void NewWord() { nWordAdd = nWordWidth = 0; }
798 };
799 
800 static bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const OUString &rText,
801  sal_Int32 nIdx, sal_Int32 nEnd )
802 {
803  bool bRet = false;
804  while( nIdx < nEnd )
805  {
806  sal_Int32 nStop = nIdx;
807  LanguageType eLang = pFnt->GetLanguage();
808  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
809 
810  bool bClear = CH_BLANK == rText[ nStop ];
811  Boundary aBndry( g_pBreakIt->GetBreakIter()->getWordBoundary( rText, nIdx,
812  g_pBreakIt->GetLocale( eLang ),
813  WordType::DICTIONARY_WORD, true ) );
814  nStop = aBndry.endPos;
815  if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
816  rArg.NewWord();
817  if( nStop == nIdx )
818  ++nStop;
819  if( nStop > nEnd )
820  nStop = nEnd;
821 
822  SwDrawTextInfo aDrawInf(rArg.pSh, *rArg.pOut, rText, nIdx, nStop - nIdx);
823  long nCurrentWidth = pFnt->GetTextSize_( aDrawInf ).Width();
824  rArg.nRowWidth += nCurrentWidth;
825  if( bClear )
826  rArg.NewWord();
827  else
828  {
829  rArg.nWordWidth += nCurrentWidth;
830  if( static_cast<long>(rArg.rAbsMin) < rArg.nWordWidth )
831  rArg.rAbsMin = rArg.nWordWidth;
832  rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
833  bRet = true;
834  }
835  nIdx = nStop;
836  }
837  return bRet;
838 }
839 
840 bool SwTextNode::IsSymbolAt(const sal_Int32 nBegin) const
841 {
842  SwScriptInfo aScriptInfo;
843  SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
844  aIter.Seek( TextFrameIndex(nBegin) );
845  return aIter.GetFnt()->IsSymbol( getIDocumentLayoutAccess().GetCurrentViewShell() );
846 }
847 
849 {
850 public:
851  sal_uLong nMaxWidth; // sum of all frame widths
852  long nMinWidth; // biggest frame
853  long nLeftRest; // space not already covered by frames in the left margin
854  long nRightRest; // space not already covered by frames in the right margin
855  long nLeftDiff; // Min/Max-difference of the frame in the left margin
856  long nRightDiff; // Min/Max-difference of the frame in the right margin
857  sal_uLong nIndx; // index of the node
858  void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
859 };
860 
862 {
863  const SwFormatAnchor& rFormatA = pNd->GetAnchor();
864 
865  if ((RndStdIds::FLY_AT_PARA != rFormatA.GetAnchorId()) &&
866  (RndStdIds::FLY_AT_CHAR != rFormatA.GetAnchorId()))
867  {
868  return;
869  }
870 
871  const SwPosition *pPos = rFormatA.GetContentAnchor();
872  OSL_ENSURE(pPos && pIn, "Unexpected NULL arguments");
873  if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
874  return;
875 
876  long nMin, nMax;
877  SwHTMLTableLayout *pLayout = nullptr;
878  const bool bIsDrawFrameFormat = pNd->Which()==RES_DRAWFRMFMT;
879  if( !bIsDrawFrameFormat )
880  {
881  // Does the frame contain a table at the start or the end?
882  const SwNodes& rNodes = pNd->GetDoc()->GetNodes();
883  const SwFormatContent& rFlyContent = pNd->GetContent();
884  sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
885  SwTableNode* pTableNd = rNodes[nStt+1]->GetTableNode();
886  if( !pTableNd )
887  {
888  SwNode *pNd2 = rNodes[nStt];
889  pNd2 = rNodes[pNd2->EndOfSectionIndex()-1];
890  if( pNd2->IsEndNode() )
891  pTableNd = pNd2->StartOfSectionNode()->GetTableNode();
892  }
893 
894  if( pTableNd )
895  pLayout = pTableNd->GetTable().GetHTMLTableLayout();
896  }
897 
898  const SwFormatHoriOrient& rOrient = pNd->GetHoriOrient();
899  sal_Int16 eHoriOri = rOrient.GetHoriOrient();
900 
901  long nDiff;
902  if( pLayout )
903  {
904  nMin = pLayout->GetMin();
905  nMax = pLayout->GetMax();
906  nDiff = nMax - nMin;
907  }
908  else
909  {
910  if( bIsDrawFrameFormat )
911  {
912  const SdrObject* pSObj = pNd->FindSdrObject();
913  if( pSObj )
914  nMin = pSObj->GetCurrentBoundRect().GetWidth();
915  else
916  nMin = 0;
917 
918  }
919  else
920  {
921  const SwFormatFrameSize &rSz = pNd->GetFrameSize();
922  nMin = rSz.GetWidth();
923  }
924  nMax = nMin;
925  nDiff = 0;
926  }
927 
928  const SvxLRSpaceItem &rLR = pNd->GetLRSpace();
929  nMin += rLR.GetLeft();
930  nMin += rLR.GetRight();
931  nMax += rLR.GetLeft();
932  nMax += rLR.GetRight();
933 
934  if( css::text::WrapTextMode_THROUGH == pNd->GetSurround().GetSurround() )
935  {
936  pIn->Minimum( nMin );
937  return;
938  }
939 
940  // Frames, which are left- or right-aligned are only party considered
941  // when calculating the maximum, since the border is already being considered.
942  // Only if the frame extends into the text body, this part is being added
943  switch( eHoriOri )
944  {
946  {
947  if( nDiff )
948  {
949  pIn->nRightRest -= pIn->nRightDiff;
950  pIn->nRightDiff = nDiff;
951  }
952  if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
953  {
954  if( pIn->nRightRest > 0 )
955  pIn->nRightRest = 0;
956  }
957  pIn->nRightRest -= nMin;
958  break;
959  }
961  {
962  if( nDiff )
963  {
964  pIn->nLeftRest -= pIn->nLeftDiff;
965  pIn->nLeftDiff = nDiff;
966  }
967  if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
968  pIn->nLeftRest < 0 )
969  pIn->nLeftRest = 0;
970  pIn->nLeftRest -= nMin;
971  break;
972  }
973  default:
974  {
975  pIn->nMaxWidth += nMax;
976  pIn->Minimum( nMin );
977  }
978  }
979 }
980 
981 #define FLYINCNT_MIN_WIDTH 284
982 
988  sal_uLong& rAbsMin ) const
989 {
991  OutputDevice* pOut = nullptr;
992  if( pSh )
993  pOut = pSh->GetWin();
994  if( !pOut )
996 
997  MapMode aOldMap( pOut->GetMapMode() );
998  pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
999 
1000  rMin = 0;
1001  rMax = 0;
1002  rAbsMin = 0;
1003 
1004  const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
1005  long nLROffset = rSpace.GetTextLeft() + GetLeftMarginWithNum( true );
1006  short nFLOffs;
1007  // For enumerations a negative first line indentation is probably filled already
1008  if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
1009  nLROffset = nFLOffs;
1010 
1011  SwMinMaxNodeArgs aNodeArgs;
1012  aNodeArgs.nMinWidth = 0;
1013  aNodeArgs.nMaxWidth = 0;
1014  aNodeArgs.nLeftRest = nLROffset;
1015  aNodeArgs.nRightRest = rSpace.GetRight();
1016  aNodeArgs.nLeftDiff = 0;
1017  aNodeArgs.nRightDiff = 0;
1018  if( nIndex )
1019  {
1020  SwFrameFormats* pTmp = const_cast<SwFrameFormats*>(GetDoc()->GetSpzFrameFormats());
1021  if( pTmp )
1022  {
1023  aNodeArgs.nIndx = nIndex;
1024  for( SwFrameFormat *pFormat : *pTmp )
1025  lcl_MinMaxNode( pFormat, &aNodeArgs );
1026  }
1027  }
1028  if( aNodeArgs.nLeftRest < 0 )
1029  aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
1030  aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
1031  if( aNodeArgs.nLeftRest < 0 )
1032  aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
1033 
1034  if( aNodeArgs.nRightRest < 0 )
1035  aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
1036  aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
1037  if( aNodeArgs.nRightRest < 0 )
1038  aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
1039 
1040  SwScriptInfo aScriptInfo;
1041  SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
1042  TextFrameIndex nIdx(0);
1043  aIter.SeekAndChgAttrIter( nIdx, pOut );
1044  TextFrameIndex nLen(m_Text.getLength());
1045  long nCurrentWidth = 0;
1046  long nAdd = 0;
1047  SwMinMaxArgs aArg( pOut, pSh, rMin, rAbsMin );
1048  while( nIdx < nLen )
1049  {
1050  TextFrameIndex nNextChg = aIter.GetNextAttr();
1051  TextFrameIndex nStop = aScriptInfo.NextScriptChg( nIdx );
1052  if( nNextChg > nStop )
1053  nNextChg = nStop;
1054  SwTextAttr *pHint = nullptr;
1055  sal_Unicode cChar = CH_BLANK;
1056  nStop = nIdx;
1057  while( nStop < nLen && nStop < nNextChg &&
1058  CH_TAB != (cChar = m_Text[sal_Int32(nStop)]) &&
1059  CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
1060  CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
1061  !pHint )
1062  {
1063  if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
1064  || ( nullptr == ( pHint = aIter.GetAttr( nStop ) ) ) )
1065  ++nStop;
1066  }
1067  if (lcl_MinMaxString(aArg, aIter.GetFnt(), m_Text, sal_Int32(nIdx), sal_Int32(nStop)))
1068  {
1069  nAdd = 20;
1070  }
1071  nIdx = nStop;
1072  aIter.SeekAndChgAttrIter( nIdx, pOut );
1073  switch( cChar )
1074  {
1075  case CH_BREAK :
1076  {
1077  if( static_cast<long>(rMax) < aArg.nRowWidth )
1078  rMax = aArg.nRowWidth;
1079  aArg.nRowWidth = 0;
1080  aArg.NewWord();
1081  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1082  }
1083  break;
1084  case CH_TAB :
1085  {
1086  aArg.NewWord();
1087  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1088  }
1089  break;
1090  case CHAR_SOFTHYPHEN:
1091  ++nIdx;
1092  break;
1093  case CHAR_HARDBLANK:
1094  case CHAR_HARDHYPHEN:
1095  {
1096  OUString sTmp( cChar );
1097  SwDrawTextInfo aDrawInf( pSh,
1098  *pOut, sTmp, 0, 1, 0, false );
1099  nCurrentWidth = aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1100  aArg.nWordWidth += nCurrentWidth;
1101  aArg.nRowWidth += nCurrentWidth;
1102  if( static_cast<long>(rAbsMin) < aArg.nWordWidth )
1103  rAbsMin = aArg.nWordWidth;
1104  aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
1105  aArg.nNoLineBreak = sal_Int32(nIdx++);
1106  }
1107  break;
1108  case CH_TXTATR_BREAKWORD:
1109  case CH_TXTATR_INWORD:
1110  {
1111  if( !pHint )
1112  break;
1113  long nOldWidth = aArg.nWordWidth;
1114  long nOldAdd = aArg.nWordAdd;
1115  aArg.NewWord();
1116 
1117  switch( pHint->Which() )
1118  {
1119  case RES_TXTATR_FLYCNT :
1120  {
1121  SwFrameFormat *pFrameFormat = pHint->GetFlyCnt().GetFrameFormat();
1122  const SvxLRSpaceItem &rLR = pFrameFormat->GetLRSpace();
1123  if( RES_DRAWFRMFMT == pFrameFormat->Which() )
1124  {
1125  const SdrObject* pSObj = pFrameFormat->FindSdrObject();
1126  if( pSObj )
1127  nCurrentWidth = pSObj->GetCurrentBoundRect().GetWidth();
1128  else
1129  nCurrentWidth = 0;
1130  }
1131  else
1132  {
1133  const SwFormatFrameSize& rTmpSize = pFrameFormat->GetFrameSize();
1134  if( RES_FLYFRMFMT == pFrameFormat->Which()
1135  && rTmpSize.GetWidthPercent() )
1136  {
1137  // This is a hack for the following situation: In the paragraph there's a
1138  // text frame with relative size. Then let's take 0.5 cm as minimum width
1139  // and USHRT_MAX as maximum width
1140  // It were cleaner and maybe necessary later on to iterate over the content
1141  // of the text frame and call GetMinMaxSize recursively
1142  nCurrentWidth = FLYINCNT_MIN_WIDTH; // 0.5 cm
1143  rMax = std::max(rMax, sal_uLong(USHRT_MAX));
1144  }
1145  else
1146  nCurrentWidth = pFrameFormat->GetFrameSize().GetWidth();
1147  }
1148  nCurrentWidth += rLR.GetLeft();
1149  nCurrentWidth += rLR.GetRight();
1150  aArg.nWordAdd = nOldWidth + nOldAdd;
1151  aArg.nWordWidth = nCurrentWidth;
1152  aArg.nRowWidth += nCurrentWidth;
1153  if( static_cast<long>(rAbsMin) < aArg.nWordWidth )
1154  rAbsMin = aArg.nWordWidth;
1155  aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
1156  break;
1157  }
1158  case RES_TXTATR_FTN :
1159  {
1160  const OUString aText = pHint->GetFootnote().GetNumStr();
1161  if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
1162  aText.getLength() ) )
1163  nAdd = 20;
1164  break;
1165  }
1166 
1167  case RES_TXTATR_FIELD :
1168  case RES_TXTATR_ANNOTATION :
1169  {
1170  SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
1171  const OUString aText = pField->ExpandField(true, nullptr);
1172  if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
1173  aText.getLength() ) )
1174  nAdd = 20;
1175  break;
1176  }
1177  default: aArg.nWordWidth = nOldWidth;
1178  aArg.nWordAdd = nOldAdd;
1179 
1180  }
1181  aIter.SeekAndChgAttrIter( ++nIdx, pOut );
1182  }
1183  break;
1184  }
1185  }
1186  if( static_cast<long>(rMax) < aArg.nRowWidth )
1187  rMax = aArg.nRowWidth;
1188 
1189  nLROffset += rSpace.GetRight();
1190 
1191  rAbsMin += nLROffset;
1192  rAbsMin += nAdd;
1193  rMin += nLROffset;
1194  rMin += nAdd;
1195  if( static_cast<long>(rMin) < aNodeArgs.nMinWidth )
1196  rMin = aNodeArgs.nMinWidth;
1197  if( static_cast<long>(rAbsMin) < aNodeArgs.nMinWidth )
1198  rAbsMin = aNodeArgs.nMinWidth;
1199  rMax += aNodeArgs.nMaxWidth;
1200  rMax += nLROffset;
1201  rMax += nAdd;
1202  if( rMax < rMin ) // e.g. Frames with flow through only contribute to the minimum
1203  rMax = rMin;
1204  pOut->SetMapMode( aOldMap );
1205 }
1206 
1217  TextFrameIndex nStart, TextFrameIndex nEnd)
1218 {
1219  assert(GetOfst() <= nStart && (!GetFollow() || nStart < GetFollow()->GetOfst()));
1220  SwViewShell const*const pSh = getRootFrame()->GetCurrShell();
1221  assert(pSh);
1222  OutputDevice *const pOut = &pSh->GetRefDev();
1223  assert(pOut);
1224 
1225  MapMode aOldMap( pOut->GetMapMode() );
1226  pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
1227 
1228  if (nStart == nEnd)
1229  {
1230  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
1231 
1232  SwScriptInfo aScriptInfo;
1233  SwAttrIter aIter(*GetTextNodeFirst(), aScriptInfo, this);
1234  aIter.SeekAndChgAttrIter( nStart, pOut );
1235 
1236  Boundary aBound = g_pBreakIt->GetBreakIter()->getWordBoundary(
1237  GetText(), sal_Int32(nStart),
1238  g_pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
1239  WordType::DICTIONARY_WORD, true );
1240 
1241  if (sal_Int32(nStart) == aBound.startPos)
1242  {
1243  // cursor is at left or right border of word
1244  pOut->SetMapMode( aOldMap );
1245  return 100;
1246  }
1247 
1248  nStart = TextFrameIndex(aBound.startPos);
1249  nEnd = TextFrameIndex(aBound.endPos);
1250 
1251  if (nStart == nEnd)
1252  {
1253  pOut->SetMapMode( aOldMap );
1254  return 100;
1255  }
1256  }
1257 
1258  SwScriptInfo aScriptInfo;
1259  SwAttrIter aIter(*GetTextNodeFirst(), aScriptInfo, this);
1260 
1261  // We do not want scaling attributes to be considered during this
1262  // calculation. For this, we push a temporary scaling attribute with
1263  // scaling value 100 and priority flag on top of the scaling stack
1264  SwAttrHandler& rAH = aIter.GetAttrHandler();
1266  SwTextAttrEnd aAttr( aItem, 0, COMPLETE_STRING );
1267  aAttr.SetPriorityAttr( true );
1268  rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
1269 
1270  TextFrameIndex nIdx = nStart;
1271 
1272  sal_uLong nWidth = 0;
1273  sal_uLong nProWidth = 0;
1274 
1275  while( nIdx < nEnd )
1276  {
1277  aIter.SeekAndChgAttrIter( nIdx, pOut );
1278 
1279  // scan for end of portion
1280  TextFrameIndex const nNextChg = std::min(aIter.GetNextAttr(), aScriptInfo.NextScriptChg(nIdx));
1281 
1282  TextFrameIndex nStop = nIdx;
1283  sal_Unicode cChar = CH_BLANK;
1284  SwTextAttr* pHint = nullptr;
1285 
1286  // stop at special characters in [ nIdx, nNextChg ]
1287  while( nStop < nEnd && nStop < nNextChg )
1288  {
1289  cChar = GetText()[sal_Int32(nStop)];
1290  if (
1291  CH_TAB == cChar ||
1292  CH_BREAK == cChar ||
1293  CHAR_HARDBLANK == cChar ||
1294  CHAR_HARDHYPHEN == cChar ||
1295  CHAR_SOFTHYPHEN == cChar ||
1296  (
1297  (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
1298  (nullptr == (pHint = aIter.GetAttr(nStop)))
1299  )
1300  )
1301  {
1302  break;
1303  }
1304  else
1305  ++nStop;
1306  }
1307 
1308  // calculate text widths up to cChar
1309  if ( nStop > nIdx )
1310  {
1311  SwDrawTextInfo aDrawInf(pSh, *pOut, GetText(), sal_Int32(nIdx), sal_Int32(nStop - nIdx));
1312  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1313  }
1314 
1315  nIdx = nStop;
1316  aIter.SeekAndChgAttrIter( nIdx, pOut );
1317 
1318  if ( cChar == CH_BREAK )
1319  {
1320  nWidth = std::max( nWidth, nProWidth );
1321  nProWidth = 0;
1322  nIdx++;
1323  }
1324  else if ( cChar == CH_TAB )
1325  {
1326  // tab receives width of one space
1327  OUString sTmp( CH_BLANK );
1328  SwDrawTextInfo aDrawInf(pSh, *pOut, sTmp, 0, 1);
1329  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1330  nIdx++;
1331  }
1332  else if ( cChar == CHAR_SOFTHYPHEN )
1333  ++nIdx;
1334  else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
1335  {
1336  OUString sTmp( cChar );
1337  SwDrawTextInfo aDrawInf(pSh, *pOut, sTmp, 0, 1);
1338  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1339  nIdx++;
1340  }
1341  else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || cChar == CH_TXTATR_INWORD ) )
1342  {
1343  switch( pHint->Which() )
1344  {
1345  case RES_TXTATR_FTN :
1346  {
1347  const OUString aText = pHint->GetFootnote().GetNumStr();
1348  SwDrawTextInfo aDrawInf(pSh, *pOut, aText, 0, aText.getLength());
1349 
1350  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1351  break;
1352  }
1353 
1354  case RES_TXTATR_FIELD :
1355  case RES_TXTATR_ANNOTATION :
1356  {
1357  SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
1358  OUString const aText = pField->ExpandField(true, getRootFrame());
1359  SwDrawTextInfo aDrawInf(pSh, *pOut, aText, 0, aText.getLength());
1360 
1361  nProWidth += aIter.GetFnt()->GetTextSize_( aDrawInf ).Width();
1362  break;
1363  }
1364 
1365  default:
1366  {
1367  // any suggestions for a default action?
1368  }
1369  } // end of switch
1370  nIdx++;
1371  } // end of while
1372  }
1373 
1374  nWidth = std::max( nWidth, nProWidth );
1375 
1376  // search for the line containing nStart
1377  if (HasPara())
1378  {
1379  SwTextInfo aInf(this);
1380  SwTextIter aLine(this, &aInf);
1381  aLine.CharToLine( nStart );
1382  pOut->SetMapMode( aOldMap );
1383  return static_cast<sal_uInt16>( nWidth ?
1384  ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1385  }
1386  // no frame or no paragraph, we take the height of the character
1387  // at nStart as line height
1388 
1389  aIter.SeekAndChgAttrIter( nStart, pOut );
1390  pOut->SetMapMode( aOldMap );
1391 
1392  SwDrawTextInfo aDrawInf(pSh, *pOut, GetText(), sal_Int32(nStart), 1);
1393  return static_cast<sal_uInt16>( nWidth ? ((100 * aIter.GetFnt()->GetTextSize_( aDrawInf ).Height()) / nWidth ) : 0 );
1394 }
1395 
1397 {
1398  SwTwips nRet = 0;
1399 
1400  sal_Int32 nIdx = 0;
1401 
1402  while ( nIdx < GetText().getLength() )
1403  {
1404  const sal_Unicode cCh = GetText()[nIdx];
1405  if ( cCh!='\t' && cCh!=' ' )
1406  {
1407  break;
1408  }
1409  ++nIdx;
1410  }
1411 
1412  if ( nIdx > 0 )
1413  {
1414  SwPosition aPos( *this );
1415  aPos.nContent += nIdx;
1416 
1417  // Find the non-follow text frame:
1419  for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1420  {
1421  // Only consider master frames:
1422  if (!pFrame->IsFollow() &&
1423  pFrame->GetTextNodeForFirstText() == this)
1424  {
1425  SwRectFnSet aRectFnSet(pFrame);
1426  SwRect aRect;
1427  pFrame->GetCharRect( aRect, aPos );
1428  nRet = pFrame->IsRightToLeft() ?
1429  aRectFnSet.GetPrtRight(*pFrame) - aRectFnSet.GetRight(aRect) :
1430  aRectFnSet.GetLeft(aRect) - aRectFnSet.GetPrtLeft(*pFrame);
1431  break;
1432  }
1433  }
1434  }
1435 
1436  return nRet;
1437 }
1438 
1439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long GetLeft() const
SwAttrHandler & GetAttrHandler()
Definition: itratr.hxx:109
long Width() const
sal_Int32 & GetStart()
start position
Definition: txatbase.hxx:77
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:786
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:3162
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:496
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:981
bool HasPara() const
Definition: txtfrm.hxx:806
long nWordAdd
Definition: itratr.cxx:791
static bool lcl_MinMaxString(SwMinMaxArgs &rArg, SwFont *pFnt, const OUString &rText, sal_Int32 nIdx, sal_Int32 nEnd)
Definition: itratr.cxx:800
long Height() const
SwNodeIndex nNode
Definition: pam.hxx:37
long GetWidth() const
void SetPriorityAttr(bool bFlag)
Definition: txatbase.hxx:93
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:3205
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:306
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:729
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:1396
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:266
void ResetFont(SwFont &rFnt) const
Definition: atrhndl.hxx:143
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:105
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1278
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:50
void SetMapMode()
const SfxPoolItem * FirstItem()
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:738
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:840
#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:793
Used by Attribute Iterators to organize attributes on stacks to find the valid attribute in each cate...
Definition: atrhndl.hxx:40
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
void SetFntChg(const bool bNew)
Definition: swfont.hxx:205
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:185
const OUString & GetNumStr() const
Definition: fmtftn.hxx:70
long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1340
long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1341
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:180
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:842
Specific frame formats (frames, DrawObjects).
Definition: docary.hxx:201
vcl::RenderContext & GetRefDev() const
Definition: viewsh.cxx:2077
bool IsFntChg() const
Definition: swfont.hxx:204
#define SAL_N_ELEMENTS(arr)
void Minimum(long nNew) const
Definition: itratr.cxx:796
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:417
void Minimum(long nNew)
Definition: itratr.cxx:858
sal_uLong & rAbsMin
Definition: itratr.cxx:788
long nWordWidth
Definition: itratr.cxx:790
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:789
VclPtr< OutputDevice > pOut
Definition: itratr.cxx:785
Count
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1170
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:1151
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:960
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:861
OUString mergedText
note: cannot be const currently to avoid UB because SwTextGuess::Guess const_casts it and modifies it...
Definition: txtfrm.hxx:958
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:456
const sal_Int32 * GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:147
#define RES_TXTATR_INETFMT
Definition: hintids.hxx:141
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:194
long GetPrtRight(const SwFrame &rFrame) const
Definition: frame.hxx:1373
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:1216
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:2044
long GetPrtLeft(const SwFrame &rFrame) const
Definition: frame.hxx:1372
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:78
void NewWord()
Definition: itratr.cxx:797
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:851
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:279
#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:987
#define RES_TXTATR_AUTOFMT
Definition: hintids.hxx:140
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:76
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:196
vcl::Window * GetWin() const
Definition: viewsh.hxx:340
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:259
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:744
SwNodes & GetNodes()
Definition: doc.hxx:403
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:792
#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:423
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:964
OutputDevice * get() const
SwFrameFormat * GetFrameFormat() const
Definition: fmtflcnt.hxx:45
sal_uLong & rMin
Definition: itratr.cxx:787
static sal_Int32 GetNextAttrImpl(SwTextNode const *pTextNode, size_t nStartIndex, size_t nEndIndex, sal_Int32 nPosition)
Definition: itratr.cxx:671
bool IsSymbol(TextFrameIndex nPos)
Definition: itratr.cxx:181
SwTextNode *const pFirstNode
except break attributes, those are taken from the first node
Definition: txtfrm.hxx:962
SwViewShell * m_pViewShell
Definition: itratr.hxx:38
#define RES_CHRATR_SCALEW
Definition: hintids.hxx:103
void SetProportion(const sal_uInt8 nNewPropr)
Definition: swfont.hxx:762
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:857
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:437
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:107
const SwFormatFlyCnt & GetFlyCnt() const
Definition: txatbase.hxx:200
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74
Base class of the Writer document model elements.
Definition: node.hxx:79