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