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

Generated by: LCOV version 1.10