LCOV - code coverage report
Current view: top level - slideshow/source/engine/shapes - drawshapesubsetting.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 248 0.4 %
Date: 2015-06-13 12:38:46 Functions: 2 29 6.9 %
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             : 
      21             : // must be first
      22             : #include <canvas/debug.hxx>
      23             : #include <tools/diagnose_ex.h>
      24             : #include <canvas/verbosetrace.hxx>
      25             : 
      26             : #include <rtl/math.hxx>
      27             : 
      28             : #include <vcl/metaact.hxx>
      29             : #include <vcl/gdimtf.hxx>
      30             : #include <basegfx/numeric/ftools.hxx>
      31             : 
      32             : #include "drawshapesubsetting.hxx"
      33             : #include "drawshape.hxx"
      34             : 
      35             : #include <boost/bind.hpp>
      36             : 
      37             : #include <algorithm>
      38             : #include <functional>
      39             : #include <limits>
      40             : 
      41             : using namespace ::com::sun::star;
      42             : 
      43             : 
      44             : namespace slideshow
      45             : {
      46             :     namespace internal
      47             :     {
      48             : 
      49             : 
      50             : 
      51             :         // Private methods
      52             : 
      53             : 
      54             : 
      55           0 :         void DrawShapeSubsetting::ensureInitializedNodeTree() const
      56             :         {
      57           0 :             ENSURE_OR_THROW( mpMtf,
      58             :                               "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
      59             : 
      60           0 :             if( mbNodeTreeInitialized )
      61           0 :                 return; // done, already initialized.
      62             : 
      63             :             // init doctree vector
      64           0 :             maActionClassVector.clear();
      65           0 :             maActionClassVector.reserve( mpMtf->GetActionSize() );
      66             : 
      67             :             // search metafile for text output
      68             :             MetaAction* pCurrAct;
      69             : 
      70           0 :             sal_Int32 nActionIndex(0);
      71           0 :             sal_Int32 nLastTextActionIndex(0);
      72           0 :             for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
      73             :             {
      74             :                 // check for one of our special text doctree comments
      75           0 :                 switch( pCurrAct->GetType() )
      76             :                 {
      77             :                     case MetaActionType::COMMENT:
      78             :                     {
      79           0 :                         MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
      80             : 
      81             :                         // skip comment if not a special XTEXT... comment
      82           0 :                         if( pAct->GetComment().matchIgnoreAsciiCase( OString("XTEXT"), 0 ) )
      83             :                         {
      84             :                             // fill classification vector with NOOPs,
      85             :                             // then insert corresponding classes at
      86             :                             // the given index
      87           0 :                             maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
      88             : 
      89           0 :                             if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOC") )
      90             :                             {
      91             :                                 // special, because can happen
      92             :                                 // in-between of portions - set
      93             :                                 // character-end classificator at
      94             :                                 // given index (relative to last text
      95             :                                 // action).
      96           0 :                                 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
      97             : 
      98           0 :                                 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
      99             :                                                   "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
     100             : 
     101           0 :                                 maActionClassVector[ nIndex ] = CLASS_CHARACTER_CELL_END;
     102             :                             }
     103           0 :                             else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOW") )
     104             :                             {
     105             :                                 // special, because can happen
     106             :                                 // in-between of portions - set
     107             :                                 // word-end classificator at given
     108             :                                 // index (relative to last text
     109             :                                 // action).
     110           0 :                                 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
     111             : 
     112           0 :                                 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
     113             :                                                   "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
     114             : 
     115           0 :                                 maActionClassVector[ nIndex ] = CLASS_WORD_END;
     116             :                             }
     117           0 :                             else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOS") )
     118             :                             {
     119             :                                 // special, because can happen
     120             :                                 // in-between of portions - set
     121             :                                 // sentence-end classificator at given
     122             :                                 // index (relative to last text
     123             :                                 // action).
     124           0 :                                 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
     125             : 
     126           0 :                                 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
     127             :                                                   "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
     128             : 
     129           0 :                                 maActionClassVector[ nIndex ] = CLASS_SENTENCE_END;
     130             :                             }
     131           0 :                             else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOL") )
     132             :                             {
     133           0 :                                 maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
     134             :                             }
     135           0 :                             else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOP") )
     136             :                             {
     137           0 :                                 maActionClassVector[ nActionIndex ] = CLASS_PARAGRAPH_END;
     138             :                             }
     139           0 :                             else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_END") )
     140             :                             {
     141           0 :                                 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
     142             :                             }
     143           0 :                             else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_BEGIN") )
     144             :                             {
     145           0 :                                 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
     146             :                             }
     147             :                         }
     148             :                         SAL_INFO(
     149             :                             "slideshow",
     150             :                             "Shape text structure: " << pAct->GetComment()
     151             :                                 << " at action #" << nActionIndex);
     152           0 :                         ++nActionIndex;
     153           0 :                         break;
     154             :                     }
     155             :                     case MetaActionType::TEXT:
     156             :                     case MetaActionType::TEXTARRAY:
     157             :                     case MetaActionType::STRETCHTEXT:
     158           0 :                         nLastTextActionIndex = nActionIndex;
     159             : #if OSL_DEBUG_LEVEL > 1
     160             :                         {
     161             :                             MetaTextAction* pText = static_cast<MetaTextAction*>(pCurrAct);
     162             :                             VERBOSE_TRACE( "Shape text \"%s\" at action #%d",
     163             :                                            OUStringToOString(pText->GetText(),
     164             :                                                       RTL_TEXTENCODING_ISO_8859_1).getStr(),
     165             :                                            nActionIndex );
     166             :                         }
     167             : #endif
     168             :                         // fallthrough intended
     169             :                     default:
     170             :                         // comment action and all actions not
     171             :                         // explicitly handled here:
     172           0 :                         nActionIndex += getNextActionOffset(pCurrAct);
     173           0 :                         break;
     174             :                 }
     175             :             }
     176             : 
     177           0 :             mbNodeTreeInitialized = true;
     178             :         }
     179             : 
     180           0 :         void DrawShapeSubsetting::updateSubsetBounds( const SubsetEntry& rSubsetEntry )
     181             :         {
     182             :             // TODO(F1): This removes too much from non-contiguous subsets
     183             :             mnMinSubsetActionIndex = ::std::min(
     184             :                 mnMinSubsetActionIndex,
     185           0 :                 rSubsetEntry.mnStartActionIndex );
     186             :             mnMaxSubsetActionIndex = ::std::max(
     187             :                 mnMaxSubsetActionIndex,
     188           0 :                 rSubsetEntry.mnEndActionIndex );
     189           0 :         }
     190             : 
     191           0 :         void DrawShapeSubsetting::updateSubsets()
     192             :         {
     193           0 :             maCurrentSubsets.clear();
     194             : 
     195           0 :             if( !maSubsetShapes.empty() )
     196             :             {
     197           0 :                 if( maSubset.isEmpty() )
     198             :                 {
     199             :                     // non-subsetted node, with some child subsets
     200             :                     // that subtract from it
     201             :                     maCurrentSubsets.push_back( DocTreeNode( 0,
     202             :                                                              mnMinSubsetActionIndex,
     203           0 :                                                              DocTreeNode::NODETYPE_INVALID ) );
     204             :                     maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
     205           0 :                                                              maActionClassVector.size(),
     206           0 :                                                              DocTreeNode::NODETYPE_INVALID ) );
     207             :                 }
     208             :                 else
     209             :                 {
     210             :                     // subsetted node, from which some further child
     211             :                     // subsets subtract content
     212             :                     maCurrentSubsets.push_back( DocTreeNode( maSubset.getStartIndex(),
     213             :                                                              mnMinSubsetActionIndex,
     214           0 :                                                              DocTreeNode::NODETYPE_INVALID ) );
     215             :                     maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
     216             :                                                              maSubset.getEndIndex(),
     217           0 :                                                              DocTreeNode::NODETYPE_INVALID ) );
     218             :                 }
     219             :             }
     220             :             else
     221             :             {
     222             :                 // no further child subsets, simply add our subset (if any)
     223           0 :                 if( !maSubset.isEmpty() )
     224             :                 {
     225             :                     // subsetted node, without any subset children
     226           0 :                     maCurrentSubsets.push_back( maSubset );
     227             :                 }
     228             :             }
     229           0 :         }
     230             : 
     231             : 
     232             : 
     233             :         // Public methods
     234             : 
     235             : 
     236             : 
     237           0 :         DrawShapeSubsetting::DrawShapeSubsetting() :
     238             :             maActionClassVector(),
     239             :             mpMtf(),
     240             :             maSubset(),
     241             :             maSubsetShapes(),
     242             :             mnMinSubsetActionIndex( SAL_MAX_INT32 ),
     243             :             mnMaxSubsetActionIndex(0),
     244             :             maCurrentSubsets(),
     245           0 :             mbNodeTreeInitialized( false )
     246             :         {
     247           0 :         }
     248             : 
     249           0 :         DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode&            rShapeSubset,
     250             :                                                   const GDIMetaFileSharedPtr&   rMtf ) :
     251             :             maActionClassVector(),
     252             :             mpMtf( rMtf ),
     253             :             maSubset( rShapeSubset ),
     254             :             maSubsetShapes(),
     255             :             mnMinSubsetActionIndex( SAL_MAX_INT32 ),
     256             :             mnMaxSubsetActionIndex(0),
     257             :             maCurrentSubsets(),
     258           0 :             mbNodeTreeInitialized( false )
     259             :         {
     260           0 :             ENSURE_OR_THROW( mpMtf,
     261             :                               "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
     262             : 
     263           0 :             initCurrentSubsets();
     264           0 :         }
     265             : 
     266           0 :         void DrawShapeSubsetting::reset()
     267             :         {
     268           0 :             maActionClassVector.clear();
     269           0 :             mpMtf.reset();
     270           0 :             maSubset.reset();
     271           0 :             maSubsetShapes.clear();
     272           0 :             mnMinSubsetActionIndex = SAL_MAX_INT32;
     273           0 :             mnMaxSubsetActionIndex = 0;
     274           0 :             maCurrentSubsets.clear();
     275           0 :             mbNodeTreeInitialized = false;
     276           0 :         }
     277             : 
     278           0 :         void DrawShapeSubsetting::reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf )
     279             :         {
     280           0 :             reset();
     281           0 :             mpMtf = rMtf;
     282             : 
     283           0 :             initCurrentSubsets();
     284           0 :         }
     285             : 
     286           0 :         void DrawShapeSubsetting::initCurrentSubsets()
     287             :         {
     288             :             // only add subset to vector, if it's not empty - that's
     289             :             // because the vector's content is later literally used
     290             :             // for e.g. painting.
     291           0 :             if( !maSubset.isEmpty() )
     292           0 :                 maCurrentSubsets.push_back( maSubset );
     293           0 :         }
     294             : 
     295           0 :         DocTreeNode DrawShapeSubsetting::getSubsetNode() const
     296             :         {
     297           0 :             return maSubset;
     298             :         }
     299             : 
     300           0 :         AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
     301             :         {
     302             :             SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
     303             : 
     304             :             // subset shape already created for this DocTreeNode?
     305           0 :             SubsetEntry aEntry;
     306             : 
     307           0 :             aEntry.mnStartActionIndex   = rTreeNode.getStartIndex();
     308           0 :             aEntry.mnEndActionIndex     = rTreeNode.getEndIndex();
     309             : 
     310           0 :             ShapeSet::const_iterator aIter;
     311           0 :             if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
     312             :             {
     313             :                 // already created, return found entry
     314           0 :                 return aIter->mpShape;
     315             :             }
     316             : 
     317           0 :             return AttributableShapeSharedPtr();
     318             :         }
     319             : 
     320           0 :         void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr& rShape )
     321             :         {
     322             :             SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
     323             : 
     324             :             // subset shape already created for this DocTreeNode?
     325           0 :             SubsetEntry aEntry;
     326           0 :             const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
     327             : 
     328           0 :             aEntry.mnStartActionIndex   = rEffectiveSubset.getStartIndex();
     329           0 :             aEntry.mnEndActionIndex     = rEffectiveSubset.getEndIndex();
     330             : 
     331           0 :             ShapeSet::const_iterator aIter;
     332           0 :             if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
     333             :             {
     334             :                 // already created, increment use count and return
     335             : 
     336             :                 // safe cast, since set order does not depend on
     337             :                 // mnSubsetQueriedCount
     338           0 :                 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
     339             :             }
     340             :             else
     341             :             {
     342             :                 // not yet created, init entry
     343           0 :                 aEntry.mnSubsetQueriedCount = 1;
     344           0 :                 aEntry.mpShape = rShape;
     345             : 
     346           0 :                 maSubsetShapes.insert( aEntry );
     347             : 
     348             :                 // update cached subset borders
     349           0 :                 updateSubsetBounds( aEntry );
     350           0 :                 updateSubsets();
     351           0 :             }
     352           0 :         }
     353             : 
     354           0 :         bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr& rShape )
     355             :         {
     356             :             SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
     357             : 
     358             :             // lookup subset shape
     359           0 :             SubsetEntry aEntry;
     360           0 :             const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
     361             : 
     362           0 :             aEntry.mnStartActionIndex   = rEffectiveSubset.getStartIndex();
     363           0 :             aEntry.mnEndActionIndex     = rEffectiveSubset.getEndIndex();
     364             : 
     365           0 :             ShapeSet::iterator aIter;
     366           0 :             if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
     367           0 :                 return false; // not found, subset was never queried
     368             : 
     369             :             // last client of the subset revoking?
     370           0 :             if( aIter->mnSubsetQueriedCount > 1 )
     371             :             {
     372             :                 // no, still clients out there. Just decrement use count
     373             :                 // safe cast, since order does not depend on mnSubsetQueriedCount
     374           0 :                 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
     375             : 
     376             :                 SAL_INFO(
     377             :                     "slideshow",
     378             :                     "Subset summary: shape " << this << ", "
     379             :                         << maSubsetShapes.size()
     380             :                         << " open subsets, revoked subset has refcount "
     381             :                         << aIter->mnSubsetQueriedCount);
     382             : 
     383           0 :                 return false; // not the last client
     384             :             }
     385             : 
     386             :             SAL_INFO(
     387             :                 "slideshow",
     388             :                 "Subset summary: shape " << this << ", "
     389             :                     << maSubsetShapes.size()
     390             :                     << " open subsets, cleared subset has range ["
     391             :                     << aEntry.mnStartActionIndex << ","
     392             :                     << aEntry.mnEndActionIndex << "]");
     393             : 
     394             :             // yes, remove from set
     395           0 :             maSubsetShapes.erase( aIter );
     396             : 
     397             : 
     398             :             // update currently active subset for _our_ shape (the
     399             :             // part of this shape that is visible, i.e. not displayed
     400             :             // in subset shapes)
     401             : 
     402             : 
     403             :             // init bounds
     404           0 :             mnMinSubsetActionIndex = SAL_MAX_INT32;
     405           0 :             mnMaxSubsetActionIndex = 0;
     406             : 
     407             :             // TODO(P2): This is quite expensive, when
     408             :             // after every subset effect end, we have to scan
     409             :             // the whole shape set
     410             : 
     411             :             // determine new subset range
     412             :             ::std::for_each( maSubsetShapes.begin(),
     413             :                              maSubsetShapes.end(),
     414             :                              ::boost::bind(&DrawShapeSubsetting::updateSubsetBounds,
     415             :                                            this,
     416           0 :                                            _1 ) );
     417             : 
     418           0 :             updateSubsets();
     419             : 
     420           0 :             return true;
     421             :         }
     422             : 
     423             :         namespace
     424             :         {
     425             :             /** Iterate over all action classification entries in the
     426             :                 given range, pass each element range found to the
     427             :                 given functor.
     428             : 
     429             :                 This method extracts, for each of the different action
     430             :                 classifications, the count and the ranges for each of
     431             :                 them, and calls the provided functor with that
     432             :                 information.
     433             : 
     434             :                 @tpl FunctorT
     435             :                 This is the functor's operator() calling signature,
     436             :                 with eCurrElemClassification denoting the current
     437             :                 classification type the functor is called for,
     438             :                 nCurrElemCount the running total of elements visited
     439             :                 for the given class (starting from 0), and
     440             :                 rCurrElemBegin/rCurrElemEnd the range of the current
     441             :                 element (i.e. the iterators from the start to the end
     442             :                 of this element).
     443             :                 <pre>
     444             :                 bool operator()( IndexClassificator                              eCurrElemClassification
     445             :                                  sal_Int32                                       nCurrElemCount,
     446             :                                  const IndexClassificatorVector::const_iterator& rCurrElemBegin,
     447             :                                  const IndexClassificatorVector::const_iterator& rCurrElemEnd );
     448             :                 </pre>
     449             :                 If the functor returns false, iteration over the
     450             :                 shapes is immediately stopped.
     451             : 
     452             :                 @param io_pFunctor
     453             :                 This functor is called for every shape found.
     454             : 
     455             :                 @param rBegin
     456             :                 Start of range to iterate over
     457             : 
     458             :                 @param rEnd
     459             :                 End of range to iterate over
     460             : 
     461             :                 @return the number of shapes found in the metafile
     462             :              */
     463           0 :             template< typename FunctorT > void iterateActionClassifications(
     464             :                 FunctorT&                                                            io_rFunctor,
     465             :                 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
     466             :                 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
     467             :             {
     468           0 :                 sal_Int32 nCurrShapeCount( 0 );
     469           0 :                 sal_Int32 nCurrParaCount( 0 );
     470           0 :                 sal_Int32 nCurrLineCount( 0 );
     471           0 :                 sal_Int32 nCurrSentenceCount( 0 );
     472           0 :                 sal_Int32 nCurrWordCount( 0 );
     473           0 :                 sal_Int32 nCurrCharCount( 0 );
     474             : 
     475           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
     476           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
     477           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
     478           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
     479           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
     480           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
     481             : 
     482           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
     483           0 :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
     484           0 :                 while( aCurr != rEnd )
     485             :                 {
     486             :                     // aNext will hold an iterator to the next element
     487             :                     // (or the past-the-end iterator, if aCurr
     488             :                     // references the last element). Used to pass a
     489             :                     // valid half-open range to the functors.
     490           0 :                     aNext = aCurr;
     491           0 :                     ++aNext;
     492             : 
     493           0 :                     switch( *aCurr )
     494             :                     {
     495             :                         default:
     496           0 :                             ENSURE_OR_THROW( false,
     497             :                                               "Unexpected type in iterateDocShapes()" );
     498             :                         case DrawShapeSubsetting::CLASS_NOOP:
     499             :                             // ignore NOOP actions
     500           0 :                             break;
     501             : 
     502             :                         case DrawShapeSubsetting::CLASS_SHAPE_START:
     503             :                             // regardless of ending action
     504             :                             // classifications before: a new shape
     505             :                             // always also starts contained elements
     506             :                             // anew
     507           0 :                             aLastShapeStart    =
     508             :                             aLastParaStart     =
     509             :                             aLastLineStart     =
     510             :                             aLastSentenceStart =
     511             :                             aLastWordStart     =
     512             :                             aLastCharStart     = aCurr;
     513           0 :                             break;
     514             : 
     515             :                         case DrawShapeSubsetting::CLASS_SHAPE_END:
     516           0 :                             if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
     517             :                                               nCurrShapeCount,
     518             :                                               aLastShapeStart,
     519           0 :                                               aNext ) )
     520             :                             {
     521           0 :                                 return;
     522             :                             }
     523             : 
     524           0 :                             ++nCurrShapeCount;
     525             :                             // FALLTHROUGH intended: shape end also
     526             :                             // ends lines
     527             :                         case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
     528           0 :                             if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
     529             :                                               nCurrParaCount,
     530             :                                               aLastParaStart,
     531           0 :                                               aNext ) )
     532             :                             {
     533           0 :                                 return;
     534             :                             }
     535             : 
     536           0 :                             ++nCurrParaCount;
     537           0 :                             aLastParaStart = aNext;
     538             :                             // FALLTHROUGH intended: para end also
     539             :                             // ends line
     540             :                         case DrawShapeSubsetting::CLASS_LINE_END:
     541           0 :                             if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
     542             :                                               nCurrLineCount,
     543             :                                               aLastLineStart,
     544           0 :                                               aNext ) )
     545             :                             {
     546           0 :                                 return;
     547             :                             }
     548             : 
     549           0 :                             ++nCurrLineCount;
     550           0 :                             aLastLineStart = aNext;
     551             : 
     552           0 :                             if( *aCurr == DrawShapeSubsetting::CLASS_LINE_END )
     553             :                             {
     554             :                                 // DON'T fall through here, as a line
     555             :                                 // does NOT end neither a sentence,
     556             :                                 // nor a word. OTOH, all parent
     557             :                                 // structures (paragraph and shape),
     558             :                                 // which itself fall through to this
     559             :                                 // code, DO end word, sentence and
     560             :                                 // character cell.
     561             : 
     562             :                                 // TODO(F1): Maybe a line should end a
     563             :                                 // character cell, OTOH?
     564           0 :                                 break;
     565             :                             }
     566             :                             // FALLTHROUGH intended
     567             :                         case DrawShapeSubsetting::CLASS_SENTENCE_END:
     568           0 :                             if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
     569             :                                               nCurrSentenceCount,
     570             :                                               aLastSentenceStart,
     571           0 :                                               aNext ) )
     572             :                             {
     573           0 :                                 return;
     574             :                             }
     575             : 
     576           0 :                             ++nCurrSentenceCount;
     577           0 :                             aLastSentenceStart = aNext;
     578             :                             // FALLTHROUGH intended
     579             :                         case DrawShapeSubsetting::CLASS_WORD_END:
     580           0 :                             if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
     581             :                                               nCurrWordCount,
     582             :                                               aLastWordStart,
     583           0 :                                               aNext ) )
     584             :                             {
     585           0 :                                 return;
     586             :                             }
     587             : 
     588           0 :                             ++nCurrWordCount;
     589           0 :                             aLastWordStart = aNext;
     590             :                             // FALLTHROUGH intended
     591             :                         case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
     592           0 :                             if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
     593             :                                               nCurrCharCount,
     594             :                                               aLastCharStart,
     595           0 :                                               aNext ) )
     596             :                             {
     597           0 :                                 return;
     598             :                             }
     599             : 
     600           0 :                             ++nCurrCharCount;
     601           0 :                             aLastCharStart = aNext;
     602           0 :                             break;
     603             :                     }
     604             : 
     605           0 :                     aCurr = aNext;
     606             :                 }
     607             :             }
     608             : 
     609           0 :             DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
     610             :             {
     611           0 :                 switch( eNodeType )
     612             :                 {
     613             :                     case DocTreeNode::NODETYPE_INVALID:
     614             :                         // FALLTHROUGH intended
     615             :                     default:
     616             :                         SAL_WARN( "slideshow", "DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
     617           0 :                         return DrawShapeSubsetting::CLASS_NOOP;
     618             : 
     619             :                     case DocTreeNode::NODETYPE_LOGICAL_SHAPE:
     620             :                         // FALLTHROUGH intended
     621             :                     case DocTreeNode::NODETYPE_FORMATTING_SHAPE:
     622           0 :                         return DrawShapeSubsetting::CLASS_SHAPE_END;
     623             : 
     624             :                     case DocTreeNode::NODETYPE_FORMATTING_LINE:
     625           0 :                         return DrawShapeSubsetting::CLASS_LINE_END;
     626             : 
     627             :                     case DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH:
     628           0 :                         return DrawShapeSubsetting::CLASS_PARAGRAPH_END;
     629             : 
     630             :                     case DocTreeNode::NODETYPE_LOGICAL_SENTENCE:
     631           0 :                         return DrawShapeSubsetting::CLASS_SENTENCE_END;
     632             : 
     633             :                     case DocTreeNode::NODETYPE_LOGICAL_WORD:
     634           0 :                         return DrawShapeSubsetting::CLASS_WORD_END;
     635             : 
     636             :                     case DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL:
     637           0 :                         return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END;
     638             :                 };
     639             :             }
     640             : 
     641             :             /// Counts number of class occurrences
     642             :             class CountClassFunctor
     643             :             {
     644             :             public:
     645           0 :                 CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
     646             :                     meClass( eClass ),
     647           0 :                     mnCurrCount(0)
     648             :                 {
     649           0 :                 }
     650             : 
     651           0 :                 bool operator()( DrawShapeSubsetting::IndexClassificator                                eCurrElemClassification,
     652             :                                  sal_Int32                                                              /*nCurrElemCount*/,
     653             :                                  const DrawShapeSubsetting::IndexClassificatorVector::const_iterator&   /*rCurrElemBegin*/,
     654             :                                  const DrawShapeSubsetting::IndexClassificatorVector::const_iterator&   /*rCurrElemEnd*/ )
     655             :                 {
     656           0 :                     if( eCurrElemClassification == meClass )
     657           0 :                         ++mnCurrCount;
     658             : 
     659           0 :                     return true; // never stop, count all occurrences
     660             :                 }
     661             : 
     662           0 :                 sal_Int32 getCount() const
     663             :                 {
     664           0 :                     return mnCurrCount;
     665             :                 }
     666             : 
     667             :             private:
     668             :                 DrawShapeSubsetting::IndexClassificator meClass;
     669             :                 sal_Int32                               mnCurrCount;
     670             :             };
     671             :         }
     672             : 
     673           0 :         sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
     674             :                                                                  const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
     675             :                                                                  DocTreeNode::NodeType                                                eNodeType )
     676             :         {
     677             :             const IndexClassificator eRequestedClass(
     678           0 :                 mapDocTreeNode( eNodeType ) );
     679             : 
     680             :             // create a counting functor for the requested class of
     681             :             // actions
     682           0 :             CountClassFunctor aFunctor( eRequestedClass );
     683             : 
     684             :             // count all occurrences in the given range
     685           0 :             iterateActionClassifications( aFunctor, rBegin, rEnd );
     686             : 
     687           0 :             return aFunctor.getCount();
     688             :         }
     689             : 
     690           0 :         sal_Int32 DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const
     691             :         {
     692           0 :             ensureInitializedNodeTree();
     693             : 
     694           0 :             return implGetNumberOfTreeNodes( maActionClassVector.begin(),
     695           0 :                                              maActionClassVector.end(),
     696           0 :                                              eNodeType );
     697             :         }
     698             : 
     699             :         namespace
     700             :         {
     701             :             /** This functor finds the nth occurrence of a given
     702             :                 action class.
     703             : 
     704             :                 The operator() compares the given index value with the
     705             :                 requested index, as given on the functor's
     706             :                 constructor. Then, the operator() returns false,
     707             :                 denoting that the requested action is found.
     708             :              */
     709             :             class FindNthElementFunctor
     710             :             {
     711             :             public:
     712           0 :                 FindNthElementFunctor( sal_Int32                                                      nNodeIndex,
     713             :                                        DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastBegin,
     714             :                                        DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastEnd,
     715             :                                        DrawShapeSubsetting::IndexClassificator                        eClass ) :
     716             :                     mnNodeIndex( nNodeIndex ),
     717             :                     mrLastBegin( rLastBegin ),
     718             :                     mrLastEnd( rLastEnd ),
     719           0 :                     meClass( eClass )
     720             :                 {
     721           0 :                 }
     722             : 
     723           0 :                 bool operator()( DrawShapeSubsetting::IndexClassificator                                eCurrElemClassification,
     724             :                                  sal_Int32                                                              nCurrElemCount,
     725             :                                  const DrawShapeSubsetting::IndexClassificatorVector::const_iterator&   rCurrElemBegin,
     726             :                                  const DrawShapeSubsetting::IndexClassificatorVector::const_iterator&   rCurrElemEnd )
     727             :                 {
     728           0 :                     if( eCurrElemClassification == meClass &&
     729           0 :                         nCurrElemCount == mnNodeIndex )
     730             :                     {
     731           0 :                         mrLastBegin = rCurrElemBegin;
     732           0 :                         mrLastEnd = rCurrElemEnd;
     733             : 
     734           0 :                         return false; // abort iteration, we've
     735             :                                       // already found what we've been
     736             :                                       // looking for
     737             :                     }
     738             : 
     739           0 :                     return true; // keep on truckin'
     740             :                 }
     741             : 
     742             :             private:
     743             :                 sal_Int32                                                       mnNodeIndex;
     744             :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator&  mrLastBegin;
     745             :                 DrawShapeSubsetting::IndexClassificatorVector::const_iterator&  mrLastEnd;
     746             :                 DrawShapeSubsetting::IndexClassificator                         meClass;
     747             :             };
     748             : 
     749           0 :             DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
     750             :                                       const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
     751             :                                       const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
     752             :                                       DocTreeNode::NodeType                                                eNodeType )
     753             :             {
     754             :                 return DocTreeNode( ::std::distance(rBegin,
     755           0 :                                                     rStart),
     756             :                                     ::std::distance(rBegin,
     757           0 :                                                     rEnd),
     758           0 :                                     eNodeType );
     759             :             }
     760             :         }
     761             : 
     762           0 :         DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator&   rBegin,
     763             :                                                           const IndexClassificatorVector::const_iterator&   rEnd,
     764             :                                                           sal_Int32                                         nNodeIndex,
     765             :                                                           DocTreeNode::NodeType                             eNodeType ) const
     766             :         {
     767             :             const IndexClassificator eRequestedClass(
     768           0 :                 mapDocTreeNode( eNodeType ) );
     769             : 
     770           0 :             DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastBegin(rEnd);
     771           0 :             DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastEnd(rEnd);
     772             : 
     773             :             // create a nth element functor for the requested class of
     774             :             // actions, and nNodeIndex as the target index
     775             :             FindNthElementFunctor aFunctor( nNodeIndex,
     776             :                                             aLastBegin,
     777             :                                             aLastEnd,
     778           0 :                                             eRequestedClass );
     779             : 
     780             :             // find given index in the given range
     781           0 :             iterateActionClassifications( aFunctor, rBegin, rEnd );
     782             : 
     783           0 :             return makeTreeNode( maActionClassVector.begin(),
     784             :                                  aLastBegin, aLastEnd,
     785           0 :                                  eNodeType );
     786             :         }
     787             : 
     788           0 :         DocTreeNode DrawShapeSubsetting::getTreeNode( sal_Int32             nNodeIndex,
     789             :                                                       DocTreeNode::NodeType eNodeType ) const
     790             :         {
     791           0 :             ensureInitializedNodeTree();
     792             : 
     793           0 :             return implGetTreeNode( maActionClassVector.begin(),
     794           0 :                                     maActionClassVector.end(),
     795             :                                     nNodeIndex,
     796           0 :                                     eNodeType );
     797             :         }
     798             : 
     799           0 :         sal_Int32 DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode&       rParentNode,
     800             :                                                                    DocTreeNode::NodeType    eNodeType ) const
     801             :         {
     802           0 :             ensureInitializedNodeTree();
     803             : 
     804             :             // convert from vector indices to vector iterators
     805           0 :             const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
     806           0 :             const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
     807           0 :             const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
     808             : 
     809             :             return implGetNumberOfTreeNodes( aParentBegin,
     810             :                                              aParentEnd,
     811           0 :                                              eNodeType );
     812             :         }
     813             : 
     814           0 :         DocTreeNode DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode&      rParentNode,
     815             :                                                             sal_Int32               nNodeIndex,
     816             :                                                             DocTreeNode::NodeType   eNodeType ) const
     817             :         {
     818           0 :             ensureInitializedNodeTree();
     819             : 
     820             :             // convert from vector indices to vector iterators
     821           0 :             const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
     822           0 :             const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
     823           0 :             const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
     824             : 
     825             :             return implGetTreeNode( aParentBegin,
     826             :                                     aParentEnd,
     827             :                                     nNodeIndex,
     828           0 :                                     eNodeType );
     829             :         }
     830             : 
     831             : 
     832             :     }
     833           3 : }
     834             : 
     835             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11