LCOV - code coverage report
Current view: top level - sw/source/core/unocore - unoportenum.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 519 566 91.7 %
Date: 2015-06-13 12:38:46 Functions: 41 46 89.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11