LibreOffice Module slideshow (master) 1
drawshapesubsetting.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <o3tl/safeint.hxx>
24
25#include <sal/log.hxx>
26#include <utility>
27#include <vcl/metaact.hxx>
28#include <vcl/gdimtf.hxx>
29
31#include "gdimtftools.hxx"
32
33#include <algorithm>
34
35using namespace ::com::sun::star;
36
37
38namespace slideshow::internal
39{
40
41
42 // Private methods
43
44
46 {
48 "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
49
51 return; // done, already initialized.
52
53 // init doctree vector
54 maActionClassVector.clear();
55 maActionClassVector.reserve( mpMtf->GetActionSize() );
56
57 // search metafile for text output
58 MetaAction* pCurrAct;
59
60 sal_Int32 nActionIndex(0);
61 sal_Int32 nLastTextActionIndex(0);
62 for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
63 {
64 // check for one of our special text doctree comments
65 switch( pCurrAct->GetType() )
66 {
67 case MetaActionType::COMMENT:
68 {
69 MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
70
71 // skip comment if not a special XTEXT... comment
72 if( pAct->GetComment().matchIgnoreAsciiCase( "XTEXT" ) )
73 {
74 // fill classification vector with NOOPs,
75 // then insert corresponding classes at
76 // the given index
77 maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
78
79 if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOC") )
80 {
81 // special, because can happen
82 // in-between of portions - set
83 // character-end classificator at
84 // given index (relative to last text
85 // action).
86 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
87
89 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
90
92 }
93 else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOW") )
94 {
95 // special, because can happen
96 // in-between of portions - set
97 // word-end classificator at given
98 // index (relative to last text
99 // action).
100 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
101
103 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
104
106 }
107 else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOS") )
108 {
109 // special, because can happen
110 // in-between of portions - set
111 // sentence-end classificator at given
112 // index (relative to last text
113 // action).
114 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
115
117 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
118
120 }
121 else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOL") )
122 {
123 maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
124 }
125 else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOP") )
126 {
128 }
129 else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_END") )
130 {
131 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
132 }
133 else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_BEGIN") )
134 {
135 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
136 }
137 }
138 SAL_INFO(
139 "slideshow",
140 "Shape text structure: " << pAct->GetComment()
141 << " at action #" << nActionIndex);
142 ++nActionIndex;
143 break;
144 }
145 case MetaActionType::TEXT:
146 case MetaActionType::TEXTARRAY:
147 case MetaActionType::STRETCHTEXT:
148 nLastTextActionIndex = nActionIndex;
149 SAL_INFO("slideshow.verbose", "Shape text \"" <<
150 (static_cast<MetaTextAction*>(pCurrAct))->GetText() <<
151 "\" at action #" << nActionIndex );
152 [[fallthrough]];
153 default:
154 // comment action and all actions not
155 // explicitly handled here:
156 nActionIndex += getNextActionOffset(pCurrAct);
157 break;
158 }
159 }
160
162 }
163
164 void DrawShapeSubsetting::excludeSubset(sal_Int32 nExcludedStart, sal_Int32 nExcludedEnd)
165 {
166 // If current subsets are empty, fill it with initial range
168 if (maCurrentSubsets.empty())
169 {
170 // Non-subsetting mode (not a subset of anything; child subsets subtract content)
171 maCurrentSubsets.emplace_back(0, maActionClassVector.size());
172 }
173
175 for (auto i = maCurrentSubsets.begin(); i != maCurrentSubsets.end();)
176 {
177 if (i->getStartIndex() < nExcludedStart)
178 {
179 if (i->getEndIndex() > nExcludedStart)
180 {
181 // Some overlap -> append new node (if required), and correct this node's end
182 if (i->getEndIndex() > nExcludedEnd)
183 {
184 aNodesToAppend.emplace_back(nExcludedEnd, i->getEndIndex());
185 }
186 i->setEndIndex(nExcludedStart);
187 }
188 ++i;
189 }
190 else if (i->getStartIndex() < nExcludedEnd)
191 {
192 if (i->getEndIndex() > nExcludedEnd)
193 {
194 // Partial overlap; change the node's start
195 i->setStartIndex(nExcludedEnd);
196 ++i;
197 }
198 else
199 {
200 // Node is fully inside the removed range: erase it
201 i = maCurrentSubsets.erase(i);
202 }
203 }
204 else
205 {
206 // Node is fully outside (after) excluded range
207 ++i;
208 }
209 }
210
211 maCurrentSubsets.insert(maCurrentSubsets.end(), aNodesToAppend.begin(),
212 aNodesToAppend.end());
213 // Excluding subsets must not leave an absolutely empty maCurrentSubsets, because it
214 // would mean "non-subsetting" mode unconditionally, with whole object added to subsets.
215 // So to indicate a subset with all parts excluded, add two empty subsets (starting and
216 // ending).
217 if (!maCurrentSubsets.empty())
218 return;
219
220 if (maSubset.isEmpty())
221 {
222 maCurrentSubsets.emplace_back(0, 0);
223 maCurrentSubsets.emplace_back(maActionClassVector.size(),
224 maActionClassVector.size());
225 }
226 else
227 {
231 }
232 }
233
235 {
236 maCurrentSubsets.clear();
238
239 for (const auto& rSubsetShape : maSubsetShapes)
240 {
241 excludeSubset(rSubsetShape.mnStartActionIndex, rSubsetShape.mnEndActionIndex);
242 }
243 }
244
245
246 // Public methods
247
248
250 maActionClassVector(),
251 mpMtf(),
252 maSubset(),
253 maSubsetShapes(),
254 maCurrentSubsets(),
255 mbNodeTreeInitialized( false )
256 {
257 }
258
260 GDIMetaFileSharedPtr rMtf ) :
261 maActionClassVector(),
262 mpMtf(std::move( rMtf )),
263 maSubset( rShapeSubset ),
264 maSubsetShapes(),
265 maCurrentSubsets(),
266 mbNodeTreeInitialized( false )
267 {
269 "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
270
272 }
273
275 {
276 maActionClassVector.clear();
277 mpMtf.reset();
278 maSubset.reset();
279 maSubsetShapes.clear();
280 maCurrentSubsets.clear();
281 mbNodeTreeInitialized = false;
282 }
283
284 void DrawShapeSubsetting::reset( const ::std::shared_ptr< GDIMetaFile >& rMtf )
285 {
286 reset();
287 mpMtf = rMtf;
288
290 }
291
293 {
294 // only add subset to vector, if vector is empty, and subset is not empty - that's
295 // because the vector's content is later literally used
296 // for e.g. painting.
297 if (maCurrentSubsets.empty() && !maSubset.isEmpty())
298 maCurrentSubsets.push_back( maSubset );
299 }
300
302 {
303 return maSubset;
304 }
305
307 {
308 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
309
310 // subset shape already created for this DocTreeNode?
311 SubsetEntry aEntry;
312
313 aEntry.mnStartActionIndex = rTreeNode.getStartIndex();
314 aEntry.mnEndActionIndex = rTreeNode.getEndIndex();
315
316 ShapeSet::const_iterator aIter;
317 if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
318 {
319 // already created, return found entry
320 return aIter->mpShape;
321 }
322
324 }
325
327 {
328 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
329
330 // subset shape already created for this DocTreeNode?
331 SubsetEntry aEntry;
332 const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
333
334 aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
335 aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
336
337 ShapeSet::const_iterator aIter;
338 if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
339 {
340 // already created, increment use count and return
341
342 // safe cast, since set order does not depend on
343 // mnSubsetQueriedCount
344 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
345 }
346 else
347 {
348 // not yet created, init entry
349 aEntry.mnSubsetQueriedCount = 1;
350 aEntry.mpShape = rShape;
351
352 maSubsetShapes.insert( aEntry );
353
355 }
356 }
357
359 {
360 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
361
362 // lookup subset shape
363 SubsetEntry aEntry;
364 const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
365
366 aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
367 aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
368
369 ShapeSet::iterator aIter;
370 if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
371 return false; // not found, subset was never queried
372
373 // last client of the subset revoking?
374 if( aIter->mnSubsetQueriedCount > 1 )
375 {
376 // no, still clients out there. Just decrement use count
377 // safe cast, since order does not depend on mnSubsetQueriedCount
378 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
379
380 SAL_INFO(
381 "slideshow",
382 "Subset summary: shape " << this << ", "
383 << maSubsetShapes.size()
384 << " open subsets, revoked subset has refcount "
385 << aIter->mnSubsetQueriedCount);
386
387 return false; // not the last client
388 }
389
390 SAL_INFO(
391 "slideshow",
392 "Subset summary: shape " << this << ", "
393 << maSubsetShapes.size()
394 << " open subsets, cleared subset has range ["
395 << aEntry.mnStartActionIndex << ","
396 << aEntry.mnEndActionIndex << "]");
397
398 // yes, remove from set
399 maSubsetShapes.erase( aIter );
400
401
402 // update currently active subset for _our_ shape (the
403 // part of this shape that is visible, i.e. not displayed
404 // in subset shapes)
405
406 // TODO(P2): This is quite expensive, when
407 // after every subset effect end, we have to scan
408 // the whole shape set
409
411
412 return true;
413 }
414
415 namespace
416 {
455 template< typename FunctorT > void iterateActionClassifications(
456 FunctorT& io_rFunctor,
457 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
458 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
459 {
460 sal_Int32 nCurrShapeCount( 0 );
461 sal_Int32 nCurrParaCount( 0 );
462 sal_Int32 nCurrLineCount( 0 );
463 sal_Int32 nCurrSentenceCount( 0 );
464 sal_Int32 nCurrWordCount( 0 );
465 sal_Int32 nCurrCharCount( 0 );
466
467 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
468 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
469 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
470 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
471 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
472 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
473
474 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
475 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
476 while( aCurr != rEnd )
477 {
478 // aNext will hold an iterator to the next element
479 // (or the past-the-end iterator, if aCurr
480 // references the last element). Used to pass a
481 // valid half-open range to the functors.
482 aNext = aCurr;
483 ++aNext;
484
485 switch( *aCurr )
486 {
487 default:
488 ENSURE_OR_THROW( false,
489 "Unexpected type in iterateDocShapes()" );
491 // ignore NOOP actions
492 break;
493
495 // regardless of ending action
496 // classifications before: a new shape
497 // always also starts contained elements
498 // anew
499 aLastShapeStart =
500 aLastParaStart =
501 aLastLineStart =
502 aLastSentenceStart =
503 aLastWordStart =
504 aLastCharStart = aCurr;
505 break;
506
508 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
509 nCurrShapeCount,
510 aLastShapeStart,
511 aNext ) )
512 {
513 return;
514 }
515
516 ++nCurrShapeCount;
517 [[fallthrough]]; // shape end also ends lines
520 nCurrParaCount,
521 aLastParaStart,
522 aNext ) )
523 {
524 return;
525 }
526
527 ++nCurrParaCount;
528 aLastParaStart = aNext;
529 [[fallthrough]]; // para end also ends line
531 if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
532 nCurrLineCount,
533 aLastLineStart,
534 aNext ) )
535 {
536 return;
537 }
538
539 ++nCurrLineCount;
540 aLastLineStart = aNext;
541
543 {
544 // DON'T fall through here, as a line
545 // does NOT end neither a sentence,
546 // nor a word. OTOH, all parent
547 // structures (paragraph and shape),
548 // which itself fall through to this
549 // code, DO end word, sentence and
550 // character cell.
551
552 // TODO(F1): Maybe a line should end a
553 // character cell, OTOH?
554 break;
555 }
556 [[fallthrough]];
559 nCurrSentenceCount,
560 aLastSentenceStart,
561 aNext ) )
562 {
563 return;
564 }
565
566 ++nCurrSentenceCount;
567 aLastSentenceStart = aNext;
568 [[fallthrough]];
570 if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
571 nCurrWordCount,
572 aLastWordStart,
573 aNext ) )
574 {
575 return;
576 }
577
578 ++nCurrWordCount;
579 aLastWordStart = aNext;
580 [[fallthrough]];
582 // tdf#113290
583 // This is a special case since a character cell
584 // (AKA grapheme cluster) can have multiple
585 // characters, so if we passed nCurrCharCount to
586 // io_rFunctor() it would stop at the first
587 // character in the cluster, so we subtract one
588 // so that it matches when we reach the start of
589 // the next cluster.
591 nCurrCharCount - 1,
592 aLastCharStart,
593 aCurr ) )
594 {
595 return;
596 }
597
598 ++nCurrCharCount;
599 aLastCharStart = aCurr;
600 break;
601 }
602
603 aCurr = aNext;
604 }
605 }
606
608 {
609 switch( eNodeType )
610 {
611 default:
612 SAL_WARN( "slideshow", "DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
614
617
620
623 };
624 }
625
627 class CountClassFunctor
628 {
629 public:
630 explicit CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
631 meClass( eClass ),
632 mnCurrCount(0)
633 {
634 }
635
636 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
637 sal_Int32 /*nCurrElemCount*/,
638 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemBegin*/,
639 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemEnd*/ )
640 {
641 if( eCurrElemClassification == meClass )
642 ++mnCurrCount;
643
644 return true; // never stop, count all occurrences
645 }
646
647 sal_Int32 getCount() const
648 {
649 return mnCurrCount;
650 }
651
652 private:
654 sal_Int32 mnCurrCount;
655 };
656 }
657
658 sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
659 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
660 DocTreeNode::NodeType eNodeType )
661 {
662 const IndexClassificator eRequestedClass(
663 mapDocTreeNode( eNodeType ) );
664
665 // create a counting functor for the requested class of
666 // actions
667 CountClassFunctor aFunctor( eRequestedClass );
668
669 // count all occurrences in the given range
670 iterateActionClassifications( aFunctor, rBegin, rEnd );
671
672 return aFunctor.getCount();
673 }
674
676 {
678
681 eNodeType );
682 }
683
684 namespace
685 {
694 class FindNthElementFunctor
695 {
696 public:
697 FindNthElementFunctor( sal_Int32 nNodeIndex,
698 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastBegin,
699 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastEnd,
701 mnNodeIndex( nNodeIndex ),
702 mrLastBegin( rLastBegin ),
703 mrLastEnd( rLastEnd ),
704 meClass( eClass )
705 {
706 }
707
708 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
709 sal_Int32 nCurrElemCount,
710 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemBegin,
711 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemEnd )
712 {
713 if( eCurrElemClassification == meClass &&
714 nCurrElemCount == mnNodeIndex )
715 {
716 mrLastBegin = rCurrElemBegin;
717 mrLastEnd = rCurrElemEnd;
718
719 return false; // abort iteration, we've
720 // already found what we've been
721 // looking for
722 }
723
724 return true; // keep on truckin'
725 }
726
727 private:
728 sal_Int32 mnNodeIndex;
729 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& mrLastBegin;
730 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& mrLastEnd;
732 };
733
734 DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
735 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
736 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
737 {
738 return DocTreeNode( ::std::distance(rBegin,
739 rStart),
740 ::std::distance(rBegin,
741 rEnd) );
742 }
743 }
744
745 DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
746 const IndexClassificatorVector::const_iterator& rEnd,
747 sal_Int32 nNodeIndex,
748 DocTreeNode::NodeType eNodeType ) const
749 {
750 const IndexClassificator eRequestedClass(
751 mapDocTreeNode( eNodeType ) );
752
753 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastBegin(rEnd);
754 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastEnd(rEnd);
755
756 // create a nth element functor for the requested class of
757 // actions, and nNodeIndex as the target index
758 FindNthElementFunctor aFunctor( nNodeIndex,
759 aLastBegin,
760 aLastEnd,
761 eRequestedClass );
762
763 // find given index in the given range
764 iterateActionClassifications( aFunctor, rBegin, rEnd );
765
766 return makeTreeNode( maActionClassVector.begin(),
767 aLastBegin, aLastEnd );
768 }
769
771 DocTreeNode::NodeType eNodeType ) const
772 {
774
775 return implGetTreeNode( maActionClassVector.begin(),
777 nNodeIndex,
778 eNodeType );
779 }
780
782 DocTreeNode::NodeType eNodeType ) const
783 {
785
786 // convert from vector indices to vector iterators
787 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
788 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
789 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
790
791 return implGetNumberOfTreeNodes( aParentBegin,
792 aParentEnd,
793 eNodeType );
794 }
795
797 sal_Int32 nNodeIndex,
798 DocTreeNode::NodeType eNodeType ) const
799 {
801
802 // convert from vector indices to vector iterators
803 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
804 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
805 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
806
807 return implGetTreeNode( aParentBegin,
808 aParentEnd,
809 nNodeIndex,
810 eNodeType );
811 }
812
813
814}
815
816/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
GDIMetaFileSharedPtr mpMtf
The metafile actually representing the Shape.
MetaActionType GetType() const
sal_Int32 GetValue() const
const OString & GetComment() const
This class represents kind of a DOM tree node for shape text.
Definition: doctreenode.hxx:45
NodeType
Type of shape entity represented by this node.
Definition: doctreenode.hxx:49
@ LogicalCharacterCell
This node represents a character.
@ LogicalWord
This node represents a word.
@ LogicalParagraph
This node represents a paragraph.
void excludeSubset(sal_Int32 nExcludedStart, sal_Int32 nExcludedEnd)
DrawShapeSubsetting()
Create empty shape subset handling.
IndexClassificator
This enum classifies each action index in the metafile.
ShapeSet maSubsetShapes
the list of subset shapes spawned from this one.
void addSubsetShape(const AttributableShapeSharedPtr &rShape)
Add child subset shape (or increase use count, if already existent)
bool mbNodeTreeInitialized
Whether the shape's doc tree has been initialized successfully, or not.
sal_Int32 getNumberOfTreeNodes(DocTreeNode::NodeType eNodeType) const
Return overall number of nodes for given type.
const DocTreeNode & getSubsetNode() const
Return subset node for this shape.
sal_Int32 getNumberOfSubsetTreeNodes(const DocTreeNode &rParentNode, DocTreeNode::NodeType eNodeType) const
Return number of nodes of given type, below parent node.
DocTreeNode getSubsetTreeNode(const DocTreeNode &rParentNode, sal_Int32 nNodeIndex, DocTreeNode::NodeType eNodeType) const
Return tree node of given index and given type, relative to parent node.
bool revokeSubsetShape(const AttributableShapeSharedPtr &rShape)
Revoke subset shape.
::std::shared_ptr< GDIMetaFile > mpMtf
Metafile to retrieve subset info from.
DocTreeNode maSubset
Subset of the metafile represented by this object.
DocTreeNode implGetTreeNode(const IndexClassificatorVector::const_iterator &rBegin, const IndexClassificatorVector::const_iterator &rEnd, sal_Int32 nNodeIndex, DocTreeNode::NodeType eNodeType) const
AttributableShapeSharedPtr getSubsetShape(const DocTreeNode &rTreeNode) const
Get subset shape for given node, if any.
static sal_Int32 implGetNumberOfTreeNodes(const IndexClassificatorVector::const_iterator &rBegin, const IndexClassificatorVector::const_iterator &rEnd, DocTreeNode::NodeType eNodeType)
VectorOfDocTreeNodes maCurrentSubsets
Current number of subsets to render (calculated from maSubset and mnMin/MaxSubsetActionIndex).
DocTreeNode getTreeNode(sal_Int32 nNodeIndex, DocTreeNode::NodeType eNodeType) const
Return tree node of given index and given type.
#define ENSURE_OR_THROW(c, m)
sal_Int32 mnNodeIndex
DrawShapeSubsetting::IndexClassificatorVector::const_iterator & mrLastEnd
sal_Int32 mnCurrCount
DrawShapeSubsetting::IndexClassificator meClass
DrawShapeSubsetting::IndexClassificatorVector::const_iterator & mrLastBegin
sal_Int32 nIndex
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
::std::vector< DocTreeNode > VectorOfDocTreeNodes
std::shared_ptr< GDIMetaFile > GDIMetaFileSharedPtr
Definition: tools.hxx:63
sal_Int32 getNextActionOffset(MetaAction *pCurrAct)
Gets the next action offset for iterating meta actions which is most often returns 1.
::std::shared_ptr< AttributableShape > AttributableShapeSharedPtr
int mnSubsetQueriedCount
Number of times this subset was queried, and not yet revoked.