LibreOffice Module sw (master)  1
unoportenum.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 #include <sal/log.hxx>
22 
23 #include <utility>
24 
25 #include <unoport.hxx>
26 #include <IMark.hxx>
27 #include <crossrefbookmark.hxx>
28 #include <annotationmark.hxx>
29 #include <doc.hxx>
31 #include <txatbase.hxx>
32 #include <txtatr.hxx>
33 #include <ndhints.hxx>
34 #include <ndtxt.hxx>
35 #include <unocrsr.hxx>
36 #include <docary.hxx>
37 #include <textboxhelper.hxx>
38 #include <tox.hxx>
39 #include <unomid.h>
40 #include <unoparaframeenum.hxx>
41 #include <unocrsrhelper.hxx>
42 #include <unorefmark.hxx>
43 #include <unobookmark.hxx>
44 #include <unoredline.hxx>
45 #include <unofield.hxx>
46 #include <unometa.hxx>
47 #include <fmtfld.hxx>
48 #include <fldbas.hxx>
49 #include <fmtmeta.hxx>
50 #include <fmtanchr.hxx>
51 #include <fmtrfmrk.hxx>
52 #include <frmfmt.hxx>
53 #include <fmtflcnt.hxx>
54 #include <unoidx.hxx>
55 #include <unocoll.hxx>
56 #include <redline.hxx>
57 #include <docufld.hxx>
58 #include <txtfld.hxx>
59 #include <txtannotationfld.hxx>
60 #include <vcl/svapp.hxx>
61 #include <comphelper/string.hxx>
64 #include <com/sun/star/container/XEnumeration.hpp>
65 #include <algorithm>
66 #include <memory>
67 #include <set>
68 #include <stack>
69 
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::text;
73 using namespace ::std;
74 
75 typedef std::pair< TextRangeList_t * const, SwTextAttr const * const > PortionList_t;
76 typedef std::stack< PortionList_t > PortionStack_t;
77 
78 static void lcl_CreatePortions(
79  TextRangeList_t & i_rPortions,
80  uno::Reference< text::XText > const& i_xParentText,
81  SwUnoCursor* pUnoCursor,
82  FrameClientSortList_t & i_rFrames,
83  const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos );
84 
85 namespace
86 {
87  enum class BkmType {
88  Start, End, StartEnd
89  };
90 
91  struct SwXBookmarkPortion_Impl
92  {
93  Reference<XTextContent> xBookmark;
94  BkmType const nBkmType;
95  const SwPosition aPosition;
96 
97  SwXBookmarkPortion_Impl(uno::Reference<text::XTextContent> const& xMark,
98  const BkmType nType, SwPosition const& rPosition)
99  : xBookmark ( xMark )
100  , nBkmType ( nType )
101  , aPosition ( rPosition )
102  {
103  }
104  sal_Int32 getIndex ()
105  {
106  return aPosition.nContent.GetIndex();
107  }
108  };
109  typedef std::shared_ptr < SwXBookmarkPortion_Impl > SwXBookmarkPortion_ImplSharedPtr;
110  struct BookmarkCompareStruct
111  {
112  bool operator () ( const SwXBookmarkPortion_ImplSharedPtr &r1,
113  const SwXBookmarkPortion_ImplSharedPtr &r2 ) const
114  {
115  // #i16896# for bookmark portions at the same position, the start should
116  // always precede the end. Hence compare positions, and use bookmark type
117  // as tie-breaker for same position.
118  // return ( r1->nIndex == r2->nIndex )
119  // ? ( r1->nBkmType < r2->nBkmType )
120  // : ( r1->nIndex < r2->nIndex );
121 
122  // Note that the above code does not correctly handle
123  // the case when one bookmark ends, and another begins in the same
124  // position. When this occurs, the above code will return the
125  // start of the 2nd bookmark BEFORE the end of the first bookmark
126  // See bug #i58438# for more details. The below code is correct and
127  // fixes both #i58438 and #i16896#
128  return r1->aPosition < r2->aPosition;
129  }
130  };
131  typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList;
132 
134  void lcl_FillBookmark(sw::mark::IMark* const pBkmk, const SwNodeIndex& nOwnNode, SwDoc& rDoc, SwXBookmarkPortion_ImplList& rBkmArr)
135  {
136  bool const hasOther = pBkmk->IsExpanded();
137 
138  const SwPosition& rStartPos = pBkmk->GetMarkStart();
139  if(rStartPos.nNode == nOwnNode)
140  {
141  // #i109272#: cross reference marks: need special handling!
142  ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
143  BkmType const nType = (hasOther || pCrossRefMark)
144  ? BkmType::Start : BkmType::StartEnd;
145  rBkmArr.insert(std::make_shared<SwXBookmarkPortion_Impl>(
146  SwXBookmark::CreateXBookmark(rDoc, pBkmk),
147  nType, rStartPos));
148  }
149 
150  const SwPosition& rEndPos = pBkmk->GetMarkEnd();
151  if(rEndPos.nNode == nOwnNode)
152  {
153  unique_ptr<SwPosition> pCrossRefEndPos;
154  const SwPosition* pEndPos = nullptr;
155  ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
156  if(hasOther)
157  {
158  pEndPos = &rEndPos;
159  }
160  else if (pCrossRefMark)
161  {
162  // Crossrefbookmarks only remember the start position but have to span the whole paragraph
163  pCrossRefEndPos = std::make_unique<SwPosition>(rEndPos);
164  pCrossRefEndPos->nContent = pCrossRefEndPos->nNode.GetNode().GetTextNode()->Len();
165  pEndPos = pCrossRefEndPos.get();
166  }
167  if(pEndPos)
168  {
169  rBkmArr.insert(std::make_shared<SwXBookmarkPortion_Impl>(
170  SwXBookmark::CreateXBookmark(rDoc, pBkmk),
171  BkmType::End, *pEndPos));
172  }
173  }
174  }
175 
176  void lcl_FillBookmarkArray(SwDoc& rDoc, SwUnoCursor& rUnoCursor, SwXBookmarkPortion_ImplList& rBkmArr)
177  {
178  IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
179  if(!pMarkAccess->getBookmarksCount())
180  return;
181 
182  const SwNodeIndex nOwnNode = rUnoCursor.GetPoint()->nNode;
183  SwTextNode* pTextNode = nOwnNode.GetNode().GetTextNode();
184  if (!pTextNode)
185  {
186  // no need to consider marks starting after aEndOfPara
187  SwPosition aEndOfPara(*rUnoCursor.GetPoint());
188  aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTextNode()->Len();
189  const IDocumentMarkAccess::const_iterator_t pCandidatesEnd =
190  pMarkAccess->findFirstBookmarkStartsAfter(aEndOfPara);
191 
192  // search for all bookmarks that start or end in this paragraph
193  for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin();
194  ppMark != pCandidatesEnd;
195  ++ppMark)
196  {
197  ::sw::mark::IMark* const pBkmk = *ppMark;
198  lcl_FillBookmark(pBkmk, nOwnNode, rDoc, rBkmArr);
199  }
200  }
201  else
202  {
203  // A text node already knows its marks via its SwIndexes.
205  for (const SwIndex* pIndex = pTextNode->GetFirstIndex(); pIndex; pIndex = pIndex->GetNext())
206  {
207  // Need a non-cost mark here, as we'll create a UNO wrapper around it.
208  sw::mark::IMark* pBkmk = const_cast<sw::mark::IMark*>(pIndex->GetMark());
209  if (!pBkmk)
210  continue;
212  // These are the types stored in the container otherwise accessible via getBookmarks*()
215  continue;
216  // Only handle bookmarks once, if they start and end at this node as well.
217  if (!aSeenMarks.insert(pBkmk).second)
218  continue;
219  lcl_FillBookmark(pBkmk, nOwnNode, rDoc, rBkmArr);
220  }
221  }
222  }
223 
224  class theSwXTextPortionEnumerationUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextPortionEnumerationUnoTunnelId > {};
225  struct SwAnnotationStartPortion_Impl
226  {
227 
228  uno::Reference< text::XTextField > mxAnnotationField;
229  const SwPosition maPosition;
230 
231  SwAnnotationStartPortion_Impl(
232  uno::Reference< text::XTextField > const& xAnnotationField,
233  SwPosition const& rPosition)
234  : mxAnnotationField ( xAnnotationField )
235  , maPosition ( rPosition )
236  {
237  }
238 
239  sal_Int32 getIndex ()
240  {
241  return maPosition.nContent.GetIndex();
242  }
243  };
244  typedef std::shared_ptr < SwAnnotationStartPortion_Impl > SwAnnotationStartPortion_ImplSharedPtr;
245  struct AnnotationStartCompareStruct
246  {
247  bool operator () ( const SwAnnotationStartPortion_ImplSharedPtr &r1,
248  const SwAnnotationStartPortion_ImplSharedPtr &r2 )
249  const
250  {
251  return r1->maPosition < r2->maPosition;
252  }
253  };
254  typedef std::multiset < SwAnnotationStartPortion_ImplSharedPtr, AnnotationStartCompareStruct > SwAnnotationStartPortion_ImplList;
255 
256  void lcl_FillAnnotationStartArray(
257  SwDoc& rDoc,
258  SwUnoCursor& rUnoCursor,
259  SwAnnotationStartPortion_ImplList& rAnnotationStartArr )
260  {
261  IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
262  if ( pMarkAccess->getAnnotationMarksCount() == 0 )
263  {
264  return;
265  }
266 
267  // no need to consider annotation marks starting after aEndOfPara
268  SwPosition aEndOfPara(*rUnoCursor.GetPoint());
269  aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTextNode()->Len();
270  const IDocumentMarkAccess::const_iterator_t pCandidatesEnd =
271  pMarkAccess->findFirstAnnotationStartsAfter(aEndOfPara);
272 
273  // search for all annotation marks that have its start position in this paragraph
274  const SwNodeIndex nOwnNode = rUnoCursor.GetPoint()->nNode;
276  ppMark != pCandidatesEnd;
277  ++ppMark )
278  {
279  ::sw::mark::AnnotationMark* const pAnnotationMark =
280  dynamic_cast< ::sw::mark::AnnotationMark* >(*ppMark);
281 
282  if (!pAnnotationMark)
283  continue;
284 
285  const SwPosition& rStartPos = pAnnotationMark->GetMarkStart();
286  if (rStartPos.nNode != nOwnNode)
287  continue;
288 
289  const SwFormatField* pAnnotationFormatField = pAnnotationMark->GetAnnotationFormatField();
290  if (!pAnnotationFormatField)
291  {
292  SAL_WARN("sw.core", "missing annotation format field");
293  continue;
294  }
295 
296  rAnnotationStartArr.insert(
297  std::make_shared<SwAnnotationStartPortion_Impl>(
299  pAnnotationFormatField),
300  rStartPos));
301  }
302  }
303 }
304 
305 const uno::Sequence< sal_Int8 > & SwXTextPortionEnumeration::getUnoTunnelId()
306 {
308 }
309 
311  const uno::Sequence< sal_Int8 >& rId )
312 {
313  if( rId.getLength() == 16
314  && 0 == memcmp( getUnoTunnelId().getConstArray(),
315  rId.getConstArray(), 16 ) )
316  {
317  return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ) );
318  }
319  return 0;
320 }
321 
323 {
324  return OUString("SwXTextPortionEnumeration");
325 }
326 
327 sal_Bool
328 SwXTextPortionEnumeration::supportsService(const OUString& rServiceName)
329 {
330  return cppu::supportsService(this, rServiceName);
331 }
332 
334 {
335  Sequence<OUString> aRet { "com.sun.star.text.TextPortionEnumeration" };
336  return aRet;
337 }
338 
340  SwPaM& rParaCursor,
341  uno::Reference< XText > const & xParentText,
342  const sal_Int32 nStart,
343  const sal_Int32 nEnd )
344  : m_Portions()
345 {
346  m_pUnoCursor = rParaCursor.GetDoc()->CreateUnoCursor(*rParaCursor.GetPoint());
347 
348  OSL_ENSURE(nEnd == -1 || (nStart <= nEnd &&
349  nEnd <= m_pUnoCursor->Start()->nNode.GetNode().GetTextNode()->GetText().getLength()),
350  "start or end value invalid!");
351 
352  // find all frames, graphics and OLEs that are bound AT character in para
353  FrameClientSortList_t frames;
354  ::CollectFrameAtNode(m_pUnoCursor->GetPoint()->nNode, frames, true);
355  lcl_CreatePortions(m_Portions, xParentText, &*m_pUnoCursor, frames, nStart, nEnd);
356 }
357 
359  SwPaM& rParaCursor,
360  TextRangeList_t const & rPortions )
361  : m_Portions( rPortions )
362 {
363  m_pUnoCursor = rParaCursor.GetDoc()->CreateUnoCursor(*rParaCursor.GetPoint());
364 }
365 
367 {
368  SolarMutexGuard aGuard;
369  m_pUnoCursor.reset(nullptr);
370 }
371 
373 {
374  SolarMutexGuard aGuard;
375 
376  return !m_Portions.empty();
377 }
378 
380 {
381  SolarMutexGuard aGuard;
382 
383  if (m_Portions.empty())
384  throw container::NoSuchElementException();
385 
386  Any any;
387  any <<= m_Portions.front();
388  m_Portions.pop_front();
389  return any;
390 }
391 
392 static void
393 lcl_FillFieldMarkArray(std::deque<sal_Int32> & rFieldMarks, SwUnoCursor const & rUnoCursor,
394  const sal_Int32 i_nStartPos)
395 {
396  const SwTextNode * const pTextNode =
397  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
398  if (!pTextNode) return;
399 
400  const sal_Unicode fld[] = {
402  sal_Int32 pos = std::max(static_cast<sal_Int32>(0), i_nStartPos);
403  while ((pos = ::comphelper::string::indexOfAny(pTextNode->GetText(), fld, pos)) != -1)
404  {
405  rFieldMarks.push_back(pos);
406  ++pos;
407  }
408 }
409 
410 static uno::Reference<text::XTextRange>
412  uno::Reference< text::XText > const & i_xParentText,
413  SwUnoCursor * const pUnoCursor,
414  const SwTextNode * const pTextNode )
415 {
416  uno::Reference<text::XTextRange> xRef;
417  SwDoc* pDoc = pUnoCursor->GetDoc();
418  // maybe it's a good idea to add a special hint to the hints array and rely on the hint segmentation....
419  const sal_Int32 start = pUnoCursor->Start()->nContent.GetIndex();
420  OSL_ENSURE(pUnoCursor->End()->nContent.GetIndex() == start,
421  "hmm --- why is this different");
422 
423  pUnoCursor->Right(1);
424  if ( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
425  {
426  OSL_FAIL("cannot move cursor?");
427  return nullptr;
428  }
429 
430  const sal_Unicode Char = pTextNode->GetText()[start];
431  if (CH_TXT_ATR_FIELDSTART == Char)
432  {
433  ::sw::mark::IFieldmark* pFieldmark = nullptr;
434  if (pDoc)
435  {
436  pFieldmark = pDoc->getIDocumentMarkAccess()->
437  getFieldmarkFor(*pUnoCursor->GetMark());
438  }
439  SwXTextPortion* pPortion = new SwXTextPortion(
440  pUnoCursor, i_xParentText, PORTION_FIELD_START);
441  xRef = pPortion;
442  if (pFieldmark && pDoc)
443  {
444  pPortion->SetBookmark(
445  SwXFieldmark::CreateXFieldmark(*pDoc, pFieldmark));
446  }
447  }
448  else if (CH_TXT_ATR_FIELDEND == Char)
449  {
450  ::sw::mark::IFieldmark* pFieldmark = nullptr;
451  if (pDoc)
452  {
453  pFieldmark = pDoc->getIDocumentMarkAccess()->
454  getFieldmarkFor(*pUnoCursor->GetMark());
455  }
456  SwXTextPortion* pPortion = new SwXTextPortion(
457  pUnoCursor, i_xParentText, PORTION_FIELD_END);
458  xRef = pPortion;
459  if (pFieldmark && pDoc)
460  {
461  pPortion->SetBookmark(
462  SwXFieldmark::CreateXFieldmark(*pDoc, pFieldmark));
463  }
464  }
465  else if (CH_TXT_ATR_FORMELEMENT == Char)
466  {
467  ::sw::mark::IFieldmark* pFieldmark = nullptr;
468  if (pDoc)
469  {
470  pFieldmark = pDoc->getIDocumentMarkAccess()->getFieldmarkFor(*pUnoCursor->GetMark());
471  }
472  SwXTextPortion* pPortion = new SwXTextPortion(
473  pUnoCursor, i_xParentText, PORTION_FIELD_START_END);
474  xRef = pPortion;
475  if (pFieldmark && pDoc)
476  {
477  pPortion->SetBookmark(
478  SwXFieldmark::CreateXFieldmark(*pDoc, pFieldmark));
479  }
480  }
481  else
482  {
483  OSL_FAIL("no fieldmark found?");
484  }
485  return xRef;
486 }
487 
488 static Reference<XTextRange>
490  Reference<XText> const& xParent,
491  const SwUnoCursor * const pUnoCursor,
492  const SwTextAttr & rAttr, const bool bEnd)
493 {
494  SwDoc* pDoc = pUnoCursor->GetDoc();
495  SwFormatRefMark& rRefMark = const_cast<SwFormatRefMark&>(
496  static_cast<const SwFormatRefMark&>(rAttr.GetAttr()));
497  Reference<XTextContent> xContent;
498  if (!xContent.is())
499  {
500  xContent = SwXReferenceMark::CreateXReferenceMark(*pDoc, &rRefMark);
501  }
502 
503  SwXTextPortion* pPortion = nullptr;
504  if (!bEnd)
505  {
506  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_START);
507  pPortion->SetRefMark(xContent);
508  pPortion->SetCollapsed(rAttr.End() == nullptr);
509  }
510  else
511  {
512  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_END);
513  pPortion->SetRefMark(xContent);
514  }
515  return pPortion;
516 }
517 
518 static void
520  TextRangeList_t & rPortions,
521  Reference<XText> const& xParent,
522  const SwUnoCursor * const pUnoCursor,
523  const SwTextAttr & rAttr, const bool bEnd)
524 {
525  SwXTextPortion* pPortion = new SwXTextPortion(pUnoCursor,
526  static_txtattr_cast<const SwTextRuby&>(rAttr), xParent, bEnd);
527  rPortions.emplace_back(pPortion);
528  pPortion->SetCollapsed(rAttr.End() == nullptr);
529 }
530 
531 static Reference<XTextRange>
533  Reference<XText> const& xParent,
534  const SwUnoCursor * const pUnoCursor,
535  SwTextAttr & rAttr, const bool bEnd)
536 {
537  SwDoc* pDoc = pUnoCursor->GetDoc();
538  SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr());
539 
540  const Reference<XTextContent> xContent(
542  uno::UNO_QUERY);
543 
544  SwXTextPortion* pPortion = nullptr;
545  if (!bEnd)
546  {
547  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_START);
548  pPortion->SetTOXMark(xContent);
549  pPortion->SetCollapsed(rAttr.GetEnd() == nullptr);
550  }
551  else
552  {
553  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_END);
554  pPortion->SetTOXMark(xContent);
555  }
556  return pPortion;
557 }
558 
559 static uno::Reference<text::XTextRange>
561  uno::Reference<text::XText> const& xParent,
562  const SwUnoCursor * const pUnoCursor,
563  SwTextAttr & rAttr, std::unique_ptr<TextRangeList_t const> && pPortions)
564 {
565  const uno::Reference<rdf::XMetadatable> xMeta( SwXMeta::CreateXMeta(
566  *static_cast<SwFormatMeta &>(rAttr.GetAttr()).GetMeta(),
567  xParent, std::move(pPortions)));
568  SwXTextPortion * pPortion(nullptr);
569  if (RES_TXTATR_META == rAttr.Which())
570  {
571  const uno::Reference<text::XTextContent> xContent(xMeta,
572  uno::UNO_QUERY);
573  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_META);
574  pPortion->SetMeta(xContent);
575  }
576  else
577  {
578  const uno::Reference<text::XTextField> xField(xMeta, uno::UNO_QUERY);
579  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_FIELD);
580  pPortion->SetTextField(xField);
581  }
582  return pPortion;
583 }
584 
599 static void lcl_ExportBookmark(
600  TextRangeList_t & rPortions,
601  Reference<XText> const& xParent,
602  const SwUnoCursor * const pUnoCursor,
603  SwXBookmarkPortion_ImplList& rBkmArr,
604  const sal_Int32 nIndex,
605  const std::set<sal_Int32>& rFramePositions,
606  bool bOnlyFrameStarts)
607 {
608  for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; )
609  {
610  const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter;
611  if ( nIndex > pPtr->getIndex() )
612  {
613  if (bOnlyFrameStarts)
614  ++aIter;
615  else
616  aIter = rBkmArr.erase(aIter);
617  continue;
618  }
619  if ( nIndex < pPtr->getIndex() )
620  break;
621 
622  if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) ||
623  (BkmType::StartEnd == pPtr->nBkmType))
624  {
625  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
626  bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts;
627  if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts)
628  {
629  // At this we create a text portion, due to one of these
630  // reasons:
631  // - this is the real start of a non-collapsed bookmark
632  // - this is the real position of a collapsed bookmark
633  // - this is the start or end (depending on bOnlyFrameStarts)
634  // of a collapsed bookmark at the same position as an at-char
635  // anchored frame
636  SwXTextPortion* pPortion =
637  new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START);
638  rPortions.emplace_back(pPortion);
639  pPortion->SetBookmark(pPtr->xBookmark);
640  pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart );
641  }
642  }
643  else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts)
644  {
645  SwXTextPortion* pPortion =
646  new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END);
647  rPortions.emplace_back(pPortion);
648  pPortion->SetBookmark(pPtr->xBookmark);
649  }
650 
651  // next bookmark
652  if (bOnlyFrameStarts)
653  ++aIter;
654  else
655  aIter = rBkmArr.erase(aIter);
656  }
657 }
658 
660  TextRangeList_t & rPortions,
661  Reference<XText> const& xParent,
662  const SwUnoCursor * const pUnoCursor,
663  SwSoftPageBreakList& rBreakArr,
664  const sal_Int32 nIndex)
665 {
666  for ( SwSoftPageBreakList::iterator aIter = rBreakArr.begin(),
667  aEnd = rBreakArr.end();
668  aIter != aEnd; )
669  {
670  if ( nIndex > *aIter )
671  {
672  aIter = rBreakArr.erase(aIter);
673  continue;
674  }
675  if ( nIndex < *aIter )
676  break;
677 
678  rPortions.push_back(
679  new SwXTextPortion(pUnoCursor, xParent, PORTION_SOFT_PAGEBREAK) );
680  aIter = rBreakArr.erase(aIter);
681  }
682 }
683 
685 {
687  const bool m_bStart;
688 
689  SwXRedlinePortion_Impl ( const SwRangeRedline* pRed, const bool bIsStart )
690  : m_pRedline(pRed)
691  , m_bStart(bIsStart)
692  {
693  }
694 
695  sal_Int32 getRealIndex ()
696  {
697  return m_bStart ? m_pRedline->Start()->nContent.GetIndex()
698  : m_pRedline->End() ->nContent.GetIndex();
699  }
700 };
701 
702 typedef std::shared_ptr < SwXRedlinePortion_Impl >
704 
706 {
708  {
709  return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End());
710  }
711 
713  const SwXRedlinePortion_ImplSharedPtr &r2 ) const
714  {
715  return getPosition ( r1 ) < getPosition ( r2 );
716  }
717 };
718 
719 typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct >
721 
722 static Reference<XTextRange>
724  PortionStack_t & rPortionStack,
725  const Reference<XText> & xParent,
726  SwUnoCursor * const pUnoCursor,
727  SwpHints const * const pHints,
728  const sal_Int32 i_nStartPos,
729  const sal_Int32 i_nEndPos,
730  const sal_Int32 nCurrentIndex,
731  const bool bRightMoveForbidden,
732  bool & o_rbCursorMoved,
733  sal_Int32 & o_rNextAttrPosition)
734 {
735  // if the attribute has a dummy character, then xRef is set (except META)
736  // otherwise, the portion for the attribute is inserted into rPortions!
737  Reference<XTextRange> xRef;
738  SwDoc* pDoc = pUnoCursor->GetDoc();
739  //search for special text attributes - first some ends
740  size_t nEndIndex = 0;
741  sal_Int32 nNextEnd = 0;
742  while(nEndIndex < pHints->Count() &&
743  (!pHints->GetSortedByEnd(nEndIndex)->GetEnd() ||
744  nCurrentIndex >= (nNextEnd = (*pHints->GetSortedByEnd(nEndIndex)->GetEnd()))))
745  {
746  if(pHints->GetSortedByEnd(nEndIndex)->GetEnd())
747  {
748  SwTextAttr * const pAttr = pHints->GetSortedByEnd(nEndIndex);
749  if (nNextEnd == nCurrentIndex)
750  {
751  const sal_uInt16 nWhich( pAttr->Which() );
752  switch (nWhich)
753  {
754  case RES_TXTATR_TOXMARK:
755  {
756  Reference<XTextRange> xTmp = lcl_CreateTOXMarkPortion(
757  xParent, pUnoCursor, *pAttr, true);
758  rPortionStack.top().first->push_back(xTmp);
759  }
760  break;
761  case RES_TXTATR_REFMARK:
762  {
763  Reference<XTextRange> xTmp = lcl_CreateRefMarkPortion(
764  xParent, pUnoCursor, *pAttr, true);
765  rPortionStack.top().first->push_back(xTmp);
766  }
767  break;
768  case RES_TXTATR_CJK_RUBY:
769  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
770  if( *pAttr->GetEnd() == pAttr->GetStart())
771  {
772  lcl_InsertRubyPortion( *rPortionStack.top().first,
773  xParent, pUnoCursor, *pAttr, false);
774  }
775  lcl_InsertRubyPortion( *rPortionStack.top().first,
776  xParent, pUnoCursor, *pAttr, true);
777  break;
778  case RES_TXTATR_META:
780  {
781  OSL_ENSURE(pAttr->GetStart() != *pAttr->GetEnd(),
782  "empty meta?");
783  if ((i_nStartPos > 0) &&
784  (pAttr->GetStart() < i_nStartPos))
785  {
786  // force skip pAttr and rest of attribute ends
787  // at nCurrentIndex
788  // because they are not contained in the meta pAttr
789  // and the meta pAttr itself is outside selection!
790  // (necessary for SwXMeta::createEnumeration)
791  if (pAttr->GetStart() + 1 == i_nStartPos)
792  {
793  nEndIndex = pHints->Count() - 1;
794  }
795  break;
796  }
797  PortionList_t Top = rPortionStack.top();
798  if (Top.second != pAttr)
799  {
800  OSL_FAIL("ExportHints: stack error" );
801  }
802  else
803  {
804  std::unique_ptr<const TextRangeList_t>
805  pCurrentPortions(Top.first);
806  rPortionStack.pop();
807  const uno::Reference<text::XTextRange> xPortion(
808  lcl_CreateMetaPortion(xParent, pUnoCursor,
809  *pAttr, std::move(pCurrentPortions)));
810  rPortionStack.top().first->push_back(xPortion);
811  }
812  }
813  break;
814  }
815  }
816  }
817  nEndIndex++;
818  }
819 
820  // then some starts
821  size_t nStartIndex = 0;
822  sal_Int32 nNextStart = 0;
823  while(nStartIndex < pHints->Count() &&
824  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
825  {
826  SwTextAttr * const pAttr = pHints->Get(nStartIndex);
827  sal_uInt16 nAttrWhich = pAttr->Which();
828  if (nNextStart == nCurrentIndex)
829  {
830  switch( nAttrWhich )
831  {
832  case RES_TXTATR_FIELD:
833  if(!bRightMoveForbidden)
834  {
835  pUnoCursor->Right(1);
836  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
837  break;
838  SwXTextPortion* pPortion;
839  xRef = pPortion =
840  new SwXTextPortion(
841  pUnoCursor, xParent, PORTION_FIELD);
842  Reference<XTextField> const xField =
844  &pAttr->GetFormatField());
845  pPortion->SetTextField(xField);
846  }
847  break;
848 
850  if(!bRightMoveForbidden)
851  {
852  pUnoCursor->Right(1);
853  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
854  break;
855 
856  const SwTextAnnotationField* pTextAnnotationField = dynamic_cast<const SwTextAnnotationField*>( pAttr );
857  ::sw::mark::IMark* pAnnotationMark = pTextAnnotationField ? pTextAnnotationField->GetAnnotationMark() : nullptr;
858  if ( pAnnotationMark != nullptr )
859  {
860  SwXTextPortion* pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION_END );
862  *pDoc, pAnnotationMark));
863  xRef = pPortion;
864  }
865  else
866  {
867  SwXTextPortion* pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
868  Reference<XTextField> xField =
870  &pAttr->GetFormatField());
871  pPortion->SetTextField(xField);
872  xRef = pPortion;
873  }
874  }
875  break;
876 
878  if(!bRightMoveForbidden)
879  {
880 
881  pUnoCursor->Right(
882  pAttr->GetFormatField().GetField()->ExpandField(true, nullptr).getLength() + 2 );
883  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
884  break;
885  SwXTextPortion* pPortion =
886  new SwXTextPortion( pUnoCursor, xParent, PORTION_FIELD);
887  xRef = pPortion;
888  Reference<XTextField> xField =
890  &pAttr->GetFormatField());
891  pPortion->SetTextField(xField);
892  }
893  break;
894 
895  case RES_TXTATR_FLYCNT:
896  if(!bRightMoveForbidden)
897  {
898  pUnoCursor->Right(1);
899  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
900  break; // Robust #i81708# content in covered cells
901 
902  // Do not expose inline anchored textboxes.
904  break;
905 
906  pUnoCursor->Exchange();
907  xRef = new SwXTextPortion( pUnoCursor, xParent, PORTION_FRAME);
908  }
909  break;
910 
911  case RES_TXTATR_FTN:
912  {
913  if(!bRightMoveForbidden)
914  {
915  pUnoCursor->Right(1);
916  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
917  break;
918  SwXTextPortion* pPortion;
919  xRef = pPortion = new SwXTextPortion(
920  pUnoCursor, xParent, PORTION_FOOTNOTE);
921  Reference<XFootnote> xContent =
922  SwXFootnotes::GetObject(*pDoc, pAttr->GetFootnote());
923  pPortion->SetFootnote(xContent);
924  }
925  }
926  break;
927 
928  case RES_TXTATR_TOXMARK:
929  case RES_TXTATR_REFMARK:
930  {
931  bool bIsPoint = !(pAttr->GetEnd());
932  if (!bRightMoveForbidden || !bIsPoint)
933  {
934  if (bIsPoint)
935  {
936  pUnoCursor->Right(1);
937  }
938  Reference<XTextRange> xTmp =
939  (RES_TXTATR_REFMARK == nAttrWhich)
941  xParent, pUnoCursor, *pAttr, false)
943  xParent, pUnoCursor, *pAttr, false);
944  if (bIsPoint) // consume CH_TXTATR!
945  {
946  pUnoCursor->Normalize(false);
947  pUnoCursor->DeleteMark();
948  xRef = xTmp;
949  }
950  else // just insert it
951  {
952  rPortionStack.top().first->push_back(xTmp);
953  }
954  }
955  }
956  break;
957  case RES_TXTATR_CJK_RUBY:
958  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
959  if(pAttr->GetEnd() && (*pAttr->GetEnd() != pAttr->GetStart()))
960  {
961  lcl_InsertRubyPortion( *rPortionStack.top().first,
962  xParent, pUnoCursor, *pAttr, false);
963  }
964  break;
965  case RES_TXTATR_META:
967  if (pAttr->GetStart() != *pAttr->GetEnd())
968  {
969  if (!bRightMoveForbidden)
970  {
971  pUnoCursor->Right(1);
972  o_rbCursorMoved = true;
973  // only if the end is included in selection!
974  if ((i_nEndPos < 0) ||
975  (*pAttr->GetEnd() <= i_nEndPos))
976  {
977  rPortionStack.push( std::make_pair(
978  new TextRangeList_t, pAttr ));
979  }
980  }
981  }
982  break;
983  case RES_TXTATR_AUTOFMT:
984  case RES_TXTATR_INETFMT:
985  case RES_TXTATR_CHARFMT:
986  break; // these are handled as properties of a "Text" portion
987  default:
988  OSL_FAIL("unknown attribute");
989  break;
990  }
991  }
992  nStartIndex++;
993  }
994 
995  if (xRef.is()) // implies that we have moved the cursor
996  {
997  o_rbCursorMoved = true;
998  }
999  if (!o_rbCursorMoved)
1000  {
1001  // search for attribute changes behind the current cursor position
1002  // break up at frames, bookmarks, redlines
1003 
1004  nStartIndex = 0;
1005  nNextStart = 0;
1006  while(nStartIndex < pHints->Count() &&
1007  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
1008  nStartIndex++;
1009 
1010  nEndIndex = 0;
1011  nNextEnd = 0;
1012  while(nEndIndex < pHints->Count() &&
1013  nCurrentIndex >= (nNextEnd = pHints->GetSortedByEnd(nEndIndex)->GetAnyEnd()))
1014  nEndIndex++;
1015 
1016  sal_Int32 nNextPos =
1017  ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd))
1018  ? nNextStart : nNextEnd;
1019  if (nNextPos > nCurrentIndex)
1020  {
1021  o_rNextAttrPosition = nNextPos;
1022  }
1023  }
1024  return xRef;
1025 }
1026 
1027 static void lcl_MoveCursor( SwUnoCursor * const pUnoCursor,
1028  const sal_Int32 nCurrentIndex,
1029  const sal_Int32 nNextFrameIndex,
1030  const sal_Int32 nNextPortionIndex,
1031  const sal_Int32 nNextAttrIndex,
1032  const sal_Int32 nNextMarkIndex,
1033  const sal_Int32 nEndPos )
1034 {
1035  sal_Int32 nMovePos = pUnoCursor->GetContentNode()->Len();
1036 
1037  if ((nEndPos >= 0) && (nEndPos < nMovePos))
1038  {
1039  nMovePos = nEndPos;
1040  }
1041 
1042  if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos))
1043  {
1044  nMovePos = nNextFrameIndex;
1045  }
1046 
1047  if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos))
1048  {
1049  nMovePos = nNextPortionIndex;
1050  }
1051 
1052  if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos))
1053  {
1054  nMovePos = nNextAttrIndex;
1055  }
1056 
1057  if ((nNextMarkIndex >= 0) && (nNextMarkIndex < nMovePos))
1058  {
1059  nMovePos = nNextMarkIndex;
1060  }
1061 
1062  if (nMovePos > nCurrentIndex)
1063  {
1064  pUnoCursor->GetPoint()->nContent = nMovePos;
1065  }
1066 }
1067 
1069  SwDoc const & rDoc,
1070  SwUnoCursor const & rUnoCursor,
1071  SwXRedlinePortion_ImplList& rRedArr )
1072 {
1073  const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable();
1074  const size_t nRedTableCount = rRedTable.size();
1075 
1076  if ( nRedTableCount > 0 )
1077  {
1078  const SwPosition* pStart = rUnoCursor.GetPoint();
1079  const SwNodeIndex nOwnNode = pStart->nNode;
1080 
1081  for(size_t nRed = 0; nRed < nRedTableCount; ++nRed)
1082  {
1083  const SwRangeRedline* pRedline = rRedTable[nRed];
1084  const SwPosition* pRedStart = pRedline->Start();
1085  const SwNodeIndex nRedNode = pRedStart->nNode;
1086  if ( nOwnNode == nRedNode )
1087  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1088  pRedline, true ) );
1089  if( pRedline->HasMark() && pRedline->End()->nNode == nOwnNode )
1090  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1091  pRedline, false ) );
1092  }
1093  }
1094 }
1095 
1097  SwUnoCursor const & rUnoCursor,
1098  SwSoftPageBreakList& rBreakArr )
1099 {
1100  const SwTextNode *pTextNode =
1101  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
1102  if( pTextNode )
1103  pTextNode->fillSoftPageBreakList( rBreakArr );
1104 }
1105 
1106 static void lcl_ExportRedline(
1107  TextRangeList_t & rPortions,
1108  Reference<XText> const& xParent,
1109  const SwUnoCursor * const pUnoCursor,
1110  SwXRedlinePortion_ImplList& rRedlineArr,
1111  const sal_Int32 nIndex)
1112 {
1113 
1114  // We want this loop to iterate over all red lines in this
1115  // array. We will only insert the ones with index matches
1116  for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end();
1117  aIter != aEnd; )
1118  {
1119  SwXRedlinePortion_ImplSharedPtr pPtr = *aIter;
1120  sal_Int32 nRealIndex = pPtr->getRealIndex();
1121  // If there are elements before nIndex, remove them
1122  if ( nIndex > nRealIndex )
1123  aIter = rRedlineArr.erase(aIter);
1124  // If the elements match, and them to the list
1125  else if ( nIndex == nRealIndex )
1126  {
1127  rPortions.push_back( new SwXRedlinePortion(
1128  *pPtr->m_pRedline, pUnoCursor, xParent, pPtr->m_bStart));
1129  aIter = rRedlineArr.erase(aIter);
1130  }
1131  // If we've iterated past nIndex, exit the loop
1132  else
1133  break;
1134  }
1135 }
1136 
1138  TextRangeList_t & rPortions,
1139  Reference<XText> const & xParent,
1140  const SwUnoCursor * const pUnoCursor,
1141  SwXBookmarkPortion_ImplList& rBkmArr,
1142  SwXRedlinePortion_ImplList& rRedlineArr,
1143  SwSoftPageBreakList& rBreakArr,
1144  const sal_Int32 nIndex,
1145  const std::set<sal_Int32>& rFramePositions,
1146  bool bOnlyFrameBookmarkStarts)
1147 {
1148  if (!rBkmArr.empty())
1149  lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions,
1150  bOnlyFrameBookmarkStarts);
1151 
1152  if (bOnlyFrameBookmarkStarts)
1153  // Only exporting the start of some collapsed bookmarks: no export of
1154  // other arrays.
1155  return;
1156 
1157  if (!rRedlineArr.empty())
1158  lcl_ExportRedline(rPortions, xParent, pUnoCursor, rRedlineArr, nIndex);
1159 
1160  if (!rBreakArr.empty())
1161  lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCursor, rBreakArr, nIndex);
1162 }
1163 
1176  TextRangeList_t & rPortions,
1177  Reference<XText> const & xParent,
1178  const SwUnoCursor * const pUnoCursor,
1179  SwAnnotationStartPortion_ImplList& rAnnotationStartArr,
1180  const sal_Int32 nIndex,
1181  const std::set<sal_Int32>& rFramePositions,
1182  bool bOnlyFrame)
1183 {
1184  for ( SwAnnotationStartPortion_ImplList::iterator aIter = rAnnotationStartArr.begin(), aEnd = rAnnotationStartArr.end();
1185  aIter != aEnd; )
1186  {
1187  SwAnnotationStartPortion_ImplSharedPtr pPtr = *aIter;
1188  if ( nIndex > pPtr->getIndex() )
1189  {
1190  aIter = rAnnotationStartArr.erase(aIter);
1191  continue;
1192  }
1193  if ( pPtr->getIndex() > nIndex )
1194  {
1195  break;
1196  }
1197 
1198  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
1199  if (bFrameStart || !bOnlyFrame)
1200  {
1201  SwXTextPortion* pPortion =
1202  new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
1203  pPortion->SetTextField( pPtr->mxAnnotationField );
1204  rPortions.emplace_back(pPortion);
1205 
1206  aIter = rAnnotationStartArr.erase(aIter);
1207  }
1208  else
1209  ++aIter;
1210  }
1211 }
1212 
1214 static void lcl_ExtractFramePositions(FrameClientSortList_t& rFrames, sal_Int32 nCurrentIndex,
1215  std::set<sal_Int32>& rFramePositions)
1216 {
1217  for (const auto& rFrame : rFrames)
1218  {
1219  if (rFrame.nIndex < nCurrentIndex)
1220  continue;
1221 
1222  if (rFrame.nIndex > nCurrentIndex)
1223  break;
1224 
1225  const SwModify* pFrame = rFrame.pFrameClient->GetRegisteredIn();
1226  if (!pFrame)
1227  continue;
1228 
1229  auto& rFormat = *static_cast<SwFrameFormat*>(const_cast<SwModify*>(pFrame));
1230  const SwFormatAnchor& rAnchor = rFormat.GetAnchor();
1231  const SwPosition* pPosition = rAnchor.GetContentAnchor();
1232  if (!pPosition)
1233  continue;
1234 
1235  rFramePositions.insert(pPosition->nContent.GetIndex());
1236  }
1237 }
1238 
1245 static sal_Int32 lcl_ExportFrames(
1246  TextRangeList_t & rPortions,
1247  Reference<XText> const & i_xParent,
1248  SwUnoCursor const * const i_pUnoCursor,
1249  FrameClientSortList_t & i_rFrames,
1250  sal_Int32 const i_nCurrentIndex)
1251 {
1252  // Ignore frames which are not exported, as we are exporting a selection
1253  // and they are anchored before the start of the selection.
1254  while (!i_rFrames.empty() && i_rFrames.front().nIndex < i_nCurrentIndex)
1255  i_rFrames.pop_front();
1256 
1257  // find first Frame in (sorted) i_rFrames at current position
1258  while (!i_rFrames.empty() && (i_rFrames.front().nIndex == i_nCurrentIndex))
1259  // do not check for i_nEnd here; this is done implicitly by lcl_MoveCursor
1260  {
1261  const SwModify * const pFrame =
1262  i_rFrames.front().pFrameClient->GetRegisteredIn();
1263  if (pFrame) // Frame could be disposed
1264  {
1265  SwXTextPortion* pPortion = new SwXTextPortion(i_pUnoCursor, i_xParent,
1266  *static_cast<SwFrameFormat*>( const_cast<SwModify*>( pFrame ) ) );
1267  rPortions.emplace_back(pPortion);
1268  }
1269  i_rFrames.pop_front();
1270  }
1271 
1272  return !i_rFrames.empty() ? i_rFrames.front().nIndex : -1;
1273 }
1274 
1275 static sal_Int32 lcl_GetNextIndex(
1276  SwXBookmarkPortion_ImplList const & rBkmArr,
1277  SwXRedlinePortion_ImplList const & rRedlineArr,
1278  SwSoftPageBreakList const & rBreakArr )
1279 {
1280  sal_Int32 nRet = -1;
1281  if(!rBkmArr.empty())
1282  {
1283  SwXBookmarkPortion_ImplSharedPtr pPtr = *rBkmArr.begin();
1284  nRet = pPtr->getIndex();
1285  }
1286  if(!rRedlineArr.empty())
1287  {
1288  SwXRedlinePortion_ImplSharedPtr pPtr = *rRedlineArr.begin();
1289  sal_Int32 nTmp = pPtr->getRealIndex();
1290  if(nRet < 0 || nTmp < nRet)
1291  nRet = nTmp;
1292  }
1293  if(!rBreakArr.empty())
1294  {
1295  if(nRet < 0 || *rBreakArr.begin() < nRet)
1296  nRet = *rBreakArr.begin();
1297  }
1298  return nRet;
1299 };
1300 
1302  TextRangeList_t & i_rPortions,
1303  uno::Reference< text::XText > const & i_xParentText,
1304  SwUnoCursor * const pUnoCursor,
1305  FrameClientSortList_t & i_rFrames,
1306  const sal_Int32 i_nStartPos,
1307  const sal_Int32 i_nEndPos )
1308 {
1309  if (!pUnoCursor)
1310  return;
1311 
1312  // set the start if a selection should be exported
1313  if ((i_nStartPos > 0) &&
1314  (pUnoCursor->Start()->nContent.GetIndex() != i_nStartPos))
1315  {
1316  pUnoCursor->DeleteMark();
1317  OSL_ENSURE(pUnoCursor->Start()->nNode.GetNode().GetTextNode() &&
1318  (i_nStartPos <= pUnoCursor->Start()->nNode.GetNode().GetTextNode()->
1319  GetText().getLength()), "Incorrect start position" );
1320  // ??? should this be i_nStartPos - current position ?
1321  pUnoCursor->Right(i_nStartPos);
1322  }
1323 
1324  SwDoc * const pDoc = pUnoCursor->GetDoc();
1325 
1326  std::deque<sal_Int32> FieldMarks;
1327  lcl_FillFieldMarkArray(FieldMarks, *pUnoCursor, i_nStartPos);
1328 
1329  SwXBookmarkPortion_ImplList Bookmarks;
1330  lcl_FillBookmarkArray(*pDoc, *pUnoCursor, Bookmarks);
1331 
1332  SwXRedlinePortion_ImplList Redlines;
1333  lcl_FillRedlineArray(*pDoc, *pUnoCursor, Redlines);
1334 
1335  SwSoftPageBreakList SoftPageBreaks;
1336  lcl_FillSoftPageBreakArray(*pUnoCursor, SoftPageBreaks);
1337 
1338  SwAnnotationStartPortion_ImplList AnnotationStarts;
1339  lcl_FillAnnotationStartArray( *pDoc, *pUnoCursor, AnnotationStarts );
1340 
1341  PortionStack_t PortionStack;
1342  PortionStack.push( PortionList_t(&i_rPortions, nullptr) );
1343 
1344  bool bAtEnd( false );
1345  while (!bAtEnd) // every iteration consumes at least current character!
1346  {
1347  if (pUnoCursor->HasMark())
1348  {
1349  pUnoCursor->Normalize(false);
1350  pUnoCursor->DeleteMark();
1351  }
1352 
1353  SwTextNode * const pTextNode = pUnoCursor->GetNode().GetTextNode();
1354  if (!pTextNode)
1355  {
1356  OSL_FAIL("lcl_CreatePortions: no TextNode - what now ?");
1357  return;
1358  }
1359 
1360  SwpHints * const pHints = pTextNode->GetpSwpHints();
1361  const sal_Int32 nCurrentIndex =
1362  pUnoCursor->GetPoint()->nContent.GetIndex();
1363  // this contains the portion which consumes the character in the
1364  // text at nCurrentIndex; i.e. it must be set _once_ per iteration
1365  uno::Reference< XTextRange > xRef;
1366 
1367  SwUnoCursorHelper::SelectPam(*pUnoCursor, true); // set mark
1368 
1369  // First remember the frame positions.
1370  std::set<sal_Int32> aFramePositions;
1371  lcl_ExtractFramePositions(i_rFrames, nCurrentIndex, aFramePositions);
1372 
1373  // Then export start of collapsed bookmarks which "cover" at-char
1374  // anchored frames.
1375  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1376  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true );
1377 
1379  *PortionStack.top().first,
1380  i_xParentText,
1381  pUnoCursor,
1382  AnnotationStarts,
1383  nCurrentIndex,
1384  aFramePositions,
1385  /*bOnlyFrame=*/true );
1386 
1387  const sal_Int32 nFirstFrameIndex =
1388  lcl_ExportFrames( *PortionStack.top().first,
1389  i_xParentText, pUnoCursor, i_rFrames, nCurrentIndex);
1390 
1391  // Export ends of the previously started collapsed bookmarks + all
1392  // other bookmarks, redlines, etc.
1393  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1394  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false );
1395 
1397  *PortionStack.top().first,
1398  i_xParentText,
1399  pUnoCursor,
1400  AnnotationStarts,
1401  nCurrentIndex,
1402  aFramePositions,
1403  /*bOnlyFrame=*/false );
1404 
1405  bool bCursorMoved( false );
1406  sal_Int32 nNextAttrIndex = -1;
1407  // #111716# the cursor must not move right at the
1408  // end position of a selection!
1409  bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos))
1410  || (nCurrentIndex >= pTextNode->Len());
1411  if (pHints)
1412  {
1413  // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor
1414  xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCursor,
1415  pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd,
1416  bCursorMoved, nNextAttrIndex);
1417  if (PortionStack.empty())
1418  {
1419  OSL_FAIL("CreatePortions: stack underflow");
1420  return;
1421  }
1422  }
1423 
1424  if (!xRef.is() && !bCursorMoved)
1425  {
1426  if (!bAtEnd &&
1427  !FieldMarks.empty() && (FieldMarks.front() == nCurrentIndex))
1428  {
1429  // moves cursor
1430  xRef = lcl_ExportFieldMark(i_xParentText, pUnoCursor, pTextNode);
1431  FieldMarks.pop_front();
1432  }
1433  }
1434  else
1435  {
1436  OSL_ENSURE(FieldMarks.empty() ||
1437  (FieldMarks.front() != nCurrentIndex),
1438  "fieldmark and hint with CH_TXTATR at same pos?");
1439  }
1440 
1441  if (!bAtEnd && !xRef.is() && !bCursorMoved)
1442  {
1443  const sal_Int32 nNextPortionIndex =
1444  lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks);
1445 
1446  sal_Int32 nNextMarkIndex = ( !FieldMarks.empty() ? FieldMarks.front() : -1 );
1447  if ( !AnnotationStarts.empty()
1448  && ( nNextMarkIndex == -1
1449  || (*AnnotationStarts.begin())->getIndex() < nNextMarkIndex ) )
1450  {
1451  nNextMarkIndex = (*AnnotationStarts.begin())->getIndex();
1452  }
1453 
1455  pUnoCursor,
1456  nCurrentIndex,
1457  nFirstFrameIndex,
1458  nNextPortionIndex,
1459  nNextAttrIndex,
1460  nNextMarkIndex,
1461  i_nEndPos );
1462 
1463  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1464  }
1465  else if (bAtEnd && !xRef.is() && !pTextNode->Len())
1466  {
1467  // special case: for an empty paragraph, we better put out a
1468  // text portion because there may be a hyperlink attribute
1469  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1470  }
1471 
1472  if (xRef.is())
1473  {
1474  PortionStack.top().first->push_back(xRef);
1475  }
1476  }
1477 
1478  OSL_ENSURE((PortionStack.size() == 1) && !PortionStack.top().second,
1479  "CreatePortions: stack error" );
1480 }
1481 
1482 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
std::deque< css::uno::Reference< css::text::XTextRange > > TextRangeList_t
Definition: unometa.hxx:42
static css::uno::Reference< css::rdf::XMetadatable > CreateXMeta(::sw::Meta &rMeta, css::uno::Reference< css::text::XText > const &xParentText=nullptr, std::unique_ptr< TextRangeList_t const > &&pPortions=std::unique_ptr< TextRangeList_t const >())
std::shared_ptr< SwUnoCursor > CreateUnoCursor(const SwPosition &rPos, bool bTableCursor=false)
Definition: doc.cxx:1807
virtual sal_Int32 Len() const
Definition: node.cxx:1183
void DeleteMark()
Definition: pam.hxx:177
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
Marks a position in the document model.
Definition: pam.hxx:35
static Reference< XTextRange > lcl_CreateTOXMarkPortion(Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwTextAttr &rAttr, const bool bEnd)
virtual css::uno::Any SAL_CALL nextElement() override
const SwField * GetField() const
Definition: fmtfld.hxx:71
#define RES_TXTATR_CJK_RUBY
Definition: hintids.hxx:143
const OUString & GetText() const
Definition: ndtxt.hxx:211
#define RES_TXTATR_METAFIELD
Definition: hintids.hxx:139
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:219
SwNodeIndex nNode
Definition: pam.hxx:37
virtual sal_Int32 getBookmarksCount() const =0
returns the number of IBookmarks.
wrapper iterator: wraps iterator of implementation while hiding MarkBase class; only IMark instances ...
std::deque< FrameClientSortListEntry > FrameClientSortList_t
static void lcl_ExportAnnotationStarts(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwAnnotationStartPortion_ImplList &rAnnotationStartArr, const sal_Int32 nIndex, const std::set< sal_Int32 > &rFramePositions, bool bOnlyFrame)
Exports all start annotation marks from rAnnotationStartArr into rPortions that have the same start p...
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:49
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:483
virtual sal_Bool SAL_CALL hasMoreElements() override
const SwPosition * GetMark() const
Definition: pam.hxx:209
Provides access to the marks of a document.
Definition: doc.hxx:185
virtual SwPosition & GetMarkStart() const override
Definition: bookmrk.hxx:65
virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition &rPos) const =0
Finds the first mark that is starting after.
virtual ~SwXTextPortionEnumeration() override
std::shared_ptr< SwXRedlinePortion_Impl > SwXRedlinePortion_ImplSharedPtr
SwNode & GetNode() const
Definition: ndindex.hxx:118
SwTextAttr * GetSortedByEnd(size_t nPos) const
Definition: ndhints.hxx:158
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1560
#define RES_TXTATR_CHARFMT
Definition: hintids.hxx:142
sal_uInt16 Which() const
Definition: txatbase.hxx:110
static css::uno::Reference< css::text::XTextField > CreateXTextField(SwDoc *pDoc, SwFormatField const *pFormat, SwServiceType nServiceId=SwServiceType::Invalid)
Definition: unofield.cxx:1259
virtual sal_Int32 getAnnotationMarksCount() const =0
sal_Int32 GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:153
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:50
const SwIndex * GetNext() const
Definition: index.hxx:102
size_type size() const
Definition: docary.hxx:368
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
#define RES_TXTATR_META
Definition: hintids.hxx:138
sal_uInt16 sal_Unicode
FUNC_TYPE const nType
SwIndex nContent
Definition: pam.hxx:38
static void lcl_FillRedlineArray(SwDoc const &rDoc, SwUnoCursor const &rUnoCursor, SwXRedlinePortion_ImplList &rRedArr)
virtual ::sw::mark::IFieldmark * getFieldmarkFor(const SwPosition &pos) const =0
bool operator()(const SwXRedlinePortion_ImplSharedPtr &r1, const SwXRedlinePortion_ImplSharedPtr &r2) const
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType)
Is the frame format a text box?
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
virtual const_iterator_t findFirstAnnotationStartsAfter(const SwPosition &rPos) const =0
Finds the first mark that is starting after.
static css::uno::Reference< css::text::XTextContent > CreateXFieldmark(SwDoc &rDoc,::sw::mark::IMark *pMark, bool isReplacementObject=false)
Definition: unobkm.cxx:651
const SwRangeRedline * m_pRedline
void SetTOXMark(css::uno::Reference< css::text::XTextContent > const &xMark)
Definition: unoport.hxx:211
static const SwPosition & getPosition(const SwXRedlinePortion_ImplSharedPtr &r)
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
void Normalize(bool bPointFirst=true)
Normalizes PaM, i.e.
Definition: pam.cxx:520
static Reference< XTextRange > lcl_CreateRefMarkPortion(Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, const SwTextAttr &rAttr, const bool bEnd)
void SelectPam(SwPaM &rPam, const bool bExpand)
Definition: unoobj.cxx:150
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
#define RES_FLYFRMFMT
Definition: hintids.hxx:274
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
void SetFootnote(css::uno::Reference< css::text::XFootnote > const &xNote)
Definition: unoport.hxx:217
static css::uno::Reference< css::text::XTextContent > CreateXBookmark(SwDoc &rDoc,::sw::mark::IMark *pBookmark)
Definition: unobkm.cxx:156
Style of a layout element.
Definition: frmfmt.hxx:57
size_t Count() const
Definition: ndhints.hxx:142
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
static void lcl_ExportRedline(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXRedlinePortion_ImplList &rRedlineArr, const sal_Int32 nIndex)
virtual OUString SAL_CALL getImplementationName() override
::sw::mark::IMark * GetAnnotationMark() const
Definition: atrfld.cxx:653
const SwPosition * GetPoint() const
Definition: pam.hxx:207
#define RES_TXTATR_FTN
Definition: hintids.hxx:152
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
void SetBookmark(css::uno::Reference< css::text::XTextContent > const &xMark)
Definition: unoport.hxx:214
Count
void Exchange()
Definition: pam.cxx:471
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
static uno::Reference< text::XTextRange > lcl_ExportFieldMark(uno::Reference< text::XText > const &i_xParentText, SwUnoCursor *const pUnoCursor, const SwTextNode *const pTextNode)
FlyAnchors.
Definition: fmtanchr.hxx:34
void CollectFrameAtNode(const SwNodeIndex &rIdx, FrameClientSortList_t &rFrames, const bool bAtCharAnchoredObjs)
Definition: unoobj2.cxx:179
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
SwDoc * GetDoc() const
Definition: pam.hxx:243
sal_Int32 indexOfAny(OUString const &rIn, sal_Unicode const *const pChars, sal_Int32 const nPos)
Marks a character position inside a document model node.
Definition: index.hxx:37
static void lcl_ExtractFramePositions(FrameClientSortList_t &rFrames, sal_Int32 nCurrentIndex, std::set< sal_Int32 > &rFramePositions)
Fills character positions from rFrames into rFramePositions.
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:52
unsigned char sal_Bool
std::pair< TextRangeList_t *const, SwTextAttr const *const > PortionList_t
Definition: unoportenum.cxx:75
static css::uno::Reference< css::text::XDocumentIndexMark > CreateXDocumentIndexMark(SwDoc &rDoc, SwTOXMark *pMark, TOXTypes eType=TOX_INDEX)
Definition: unoidx.cxx:1628
void SetTextField(css::uno::Reference< css::text::XTextField > const &xField)
Definition: unoport.hxx:220
static void lcl_InsertRubyPortion(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, const SwTextAttr &rAttr, const bool bEnd)
virtual const_iterator_t getAnnotationMarksBegin() const =0
#define RES_TXTATR_TOXMARK
Definition: hintids.hxx:137
Marks a node in the document model.
Definition: ndindex.hxx:31
void SetCollapsed(bool bSet)
Definition: unoport.hxx:226
static void lcl_ExportBookmark(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXBookmarkPortion_ImplList &rBkmArr, const sal_Int32 nIndex, const std::set< sal_Int32 > &rFramePositions, bool bOnlyFrameStarts)
Exports all bookmarks from rBkmArr into rPortions that have the same start or end position as nIndex...
std::stack< PortionList_t > PortionStack_t
Definition: unoportenum.cxx:76
DocumentType const eType
static css::uno::Reference< css::text::XTextContent > CreateXReferenceMark(SwDoc &rDoc, SwFormatRefMark *pMarkFormat)
Definition: unorefmk.cxx:131
SwXRedlinePortion_Impl(const SwRangeRedline *pRed, const bool bIsStart)
#define RES_TXTATR_INETFMT
Definition: hintids.hxx:141
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:200
static sal_Int32 lcl_GetNextIndex(SwXBookmarkPortion_ImplList const &rBkmArr, SwXRedlinePortion_ImplList const &rRedlineArr, SwSoftPageBreakList const &rBreakArr)
const SwPosition * Start() const
Definition: pam.hxx:212
BkmType
Definition: unoportenum.cxx:87
static void lcl_FillFieldMarkArray(std::deque< sal_Int32 > &rFieldMarks, SwUnoCursor const &rUnoCursor, const sal_Int32 i_nStartPos)
void fillSoftPageBreakList(SwSoftPageBreakList &rBreak) const
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
OUString ExpandField(bool bCached, SwRootFrame const *pLayout) const
expand the field.
Definition: fldbas.cxx:412
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:367
#define RES_TXTATR_FIELD
Definition: hintids.hxx:150
SwXTextPortionEnumeration(SwPaM &rParaCursor, css::uno::Reference< css::text::XText > const &xParent, const sal_Int32 nStart, const sal_Int32 nEnd)
#define RES_TXTATR_AUTOFMT
Definition: hintids.hxx:140
static void lcl_FillSoftPageBreakArray(SwUnoCursor const &rUnoCursor, SwSoftPageBreakList &rBreakArr)
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
sw::UnoCursorPointer m_pUnoCursor
Definition: unoport.hxx:242
std::multiset< SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct > SwXRedlinePortion_ImplList
std::set< sal_Int32 > SwSoftPageBreakList
Definition: wrtww8.hxx:137
void reset(std::shared_ptr< SwUnoCursor > pNew)
Definition: unocrsr.hxx:157
bool Right(sal_uInt16 nCnt)
Definition: swcrsr.hxx:171
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:153
virtual const_iterator_t getBookmarksBegin() const =0
returns a STL-like random access iterator to the begin of the sequence the IBookmarks.
sal_Int32 GetIndex() const
Definition: index.hxx:95
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &aIdentifier) override
const SwPosition * End() const
Definition: pam.hxx:217
const SwModify * GetRegisteredIn() const
Definition: calbck.hxx:157
const sal_Int32 * End() const
Definition: txatbase.hxx:148
static Reference< XTextRange > lcl_ExportHints(PortionStack_t &rPortionStack, const Reference< XText > &xParent, SwUnoCursor *const pUnoCursor, SwpHints const *const pHints, const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos, const sal_Int32 nCurrentIndex, const bool bRightMoveForbidden, bool &o_rbCursorMoved, sal_Int32 &o_rNextAttrPosition)
void SetRefMark(css::uno::Reference< css::text::XTextContent > const &xMark)
Definition: unoport.hxx:208
#define RES_TXTATR_FLYCNT
Definition: hintids.hxx:151
#define RES_TXTATR_REFMARK
Definition: hintids.hxx:136
virtual const SwPosition & GetMarkEnd() const =0
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:53
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:159
#define SAL_WARN(area, stream)
SwFrameFormat * GetFrameFormat() const
Definition: fmtflcnt.hxx:45
static void lcl_MoveCursor(SwUnoCursor *const pUnoCursor, const sal_Int32 nCurrentIndex, const sal_Int32 nNextFrameIndex, const sal_Int32 nNextPortionIndex, const sal_Int32 nNextAttrIndex, const sal_Int32 nNextMarkIndex, const sal_Int32 nEndPos)
void SetMeta(css::uno::Reference< css::text::XTextContent > const &xMeta)
Definition: unoport.hxx:223
const SwIndex * GetFirstIndex() const
Definition: index.hxx:129
virtual const SwPosition & GetMarkStart() const =0
static sal_Int32 lcl_ExportFrames(TextRangeList_t &rPortions, Reference< XText > const &i_xParent, SwUnoCursor const *const i_pUnoCursor, FrameClientSortList_t &i_rFrames, sal_Int32 const i_nCurrentIndex)
Exports at-char anchored frames.
TextRangeList_t m_Portions
Definition: unoport.hxx:241
virtual const SwRedlineTable & GetRedlineTable() const =0
std::pair< const_iterator, bool > insert(Value &&x)
virtual bool IsExpanded() const =0
#define RES_TXTATR_INPUTFIELD
Definition: hintids.hxx:145
static uno::Reference< text::XTextRange > lcl_CreateMetaPortion(uno::Reference< text::XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwTextAttr &rAttr, std::unique_ptr< TextRangeList_t const > &&pPortions)
const SwFormatField * GetAnnotationFormatField() const
static void lcl_ExportSoftPageBreak(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwSoftPageBreakList &rBreakArr, const sal_Int32 nIndex)
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:843
static css::uno::Reference< css::text::XFootnote > GetObject(SwDoc &rDoc, const SwFormatFootnote &rFormat)
Definition: unocoll.cxx:1826
static void lcl_CreatePortions(TextRangeList_t &i_rPortions, uno::Reference< text::XText > const &i_xParentText, SwUnoCursor *pUnoCursor, FrameClientSortList_t &i_rFrames, const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos)
const SwFormatFlyCnt & GetFlyCnt() const
Definition: txatbase.hxx:206
static void lcl_ExportBkmAndRedline(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXBookmarkPortion_ImplList &rBkmArr, SwXRedlinePortion_ImplList &rRedlineArr, SwSoftPageBreakList &rBreakArr, const sal_Int32 nIndex, const std::set< sal_Int32 > &rFramePositions, bool bOnlyFrameBookmarkStarts)