1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <canvas/debug.hxx>
23 #include <tools/diagnose_ex.h>
24 #include <shapeattributelayer.hxx>
26 #include <canvas/verbosetrace.hxx>
29 #include <com/sun/star/awt/Rectangle.hpp>
30 #include <com/sun/star/awt/FontUnderline.hpp>
31 #include <com/sun/star/awt/FontWeight.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/animations/AnimationAdditiveMode.hpp>
35 #include <basegfx/numeric/ftools.hxx>
36 #include <basegfx/polygon/b2dpolygon.hxx>
37 #include <rtl/math.hxx>
40 using namespace ::com::sun::star
;
49 This method updates all state IDs from possible
50 children. Whenever a child's state ID changed, we
53 void ShapeAttributeLayer::updateStateIds()
57 if( mnTransformationState
!= mpChild
->getTransformationState() )
58 ++mnTransformationState
;
59 if( mnClipState
!= mpChild
->getClipState() )
61 if( mnAlphaState
!= mpChild
->getAlphaState() )
63 if( mnPositionState
!= mpChild
->getPositionState() )
65 if( mnContentState
!= mpChild
->getContentState() )
67 if( mnVisibilityState
!= mpChild
->getVisibilityState() )
72 /** Calc attribute value.
74 This method determines the current attribute value,
75 appropriately combining it with children values (by
76 evaluating the mnAdditiveMode member).
78 template< typename T
> T
ShapeAttributeLayer::calcValue( const T
& rCurrValue
,
79 bool bThisInstanceValid
,
80 bool (ShapeAttributeLayer::*pIsValid
)() const,
81 T (ShapeAttributeLayer::*pGetValue
)() const ) const
83 // deviated from the (*shared_ptr).*mpFuncPtr notation
84 // here, since gcc does not seem to parse that as a member
85 // function call anymore.
86 const bool bChildInstanceValueValid( haveChild() && (mpChild
.get()->*pIsValid
)() );
88 if( bThisInstanceValid
)
90 if( bChildInstanceValueValid
)
92 // merge with child value
93 switch( mnAdditiveMode
)
96 // FALTHROUGH intended
97 case animations::AnimationAdditiveMode::NONE
:
98 // FALTHROUGH intended
99 case animations::AnimationAdditiveMode::BASE
:
100 // FALTHROUGH intended
101 case animations::AnimationAdditiveMode::REPLACE
:
102 // TODO(F2): reverse-engineer the semantics of these
105 // currently, treat them the same and replace
106 // the child value by our own
109 case animations::AnimationAdditiveMode::SUM
:
110 return rCurrValue
+ ((*mpChild
).*pGetValue
)();
112 case animations::AnimationAdditiveMode::MULTIPLY
:
113 return rCurrValue
* ((*mpChild
).*pGetValue
)();
118 // this object is the only one defining
119 // the value, so take it
125 return bChildInstanceValueValid
?
126 ((*mpChild
).*pGetValue
)() :
127 T(); // pass on child value, regardless
128 // if it's valid or not. If not, it's
133 ShapeAttributeLayer::ShapeAttributeLayer( const ShapeAttributeLayerSharedPtr
& rChildLayer
) :
134 mpChild( rChildLayer
),
146 mnCharRotationAngle(),
150 meFillStyle( drawing::FillStyle_NONE
),
151 meLineStyle( drawing::LineStyle_NONE
),
152 meCharPosture( awt::FontSlant_NONE
),
160 mnTransformationState( rChildLayer
? rChildLayer
->getTransformationState() : 0 ),
161 mnClipState( rChildLayer
? rChildLayer
->getClipState() : 0),
162 mnAlphaState( rChildLayer
? rChildLayer
->getAlphaState() : 0),
163 mnPositionState( rChildLayer
? rChildLayer
->getPositionState() : 0 ),
164 mnContentState( rChildLayer
? rChildLayer
->getContentState() : 0 ),
165 mnVisibilityState( rChildLayer
? rChildLayer
->getVisibilityState() : 0 ),
167 mnAdditiveMode( animations::AnimationAdditiveMode::BASE
),
169 mbVisibility( false ),
171 mbWidthValid( false ),
172 mbHeightValid( false ),
173 mbPosXValid( false ),
174 mbPosYValid( false ),
175 mbClipValid( false ),
177 mbFontFamilyValid( false ),
179 mbRotationAngleValid( false ),
180 mbShearXAngleValid( false ),
181 mbShearYAngleValid( false ),
183 mbAlphaValid( false ),
185 mbCharRotationAngleValid( false ),
186 mbCharScaleValid( false ),
188 mbDimColorValid( false ),
189 mbFillColorValid( false ),
190 mbLineColorValid( false ),
191 mbCharColorValid( false ),
193 mbFillStyleValid( false ),
194 mbLineStyleValid( false ),
195 mbCharWeightValid( false ),
196 mbUnderlineModeValid( false ),
197 mbCharPostureValid( false ),
198 mbVisibilityValid( false )
202 bool ShapeAttributeLayer::revokeChildLayer( const ShapeAttributeLayerSharedPtr
& rChildLayer
)
204 ENSURE_OR_RETURN_FALSE( rChildLayer
,
205 "ShapeAttributeLayer::revokeChildLayer(): Will not remove NULL child" );
208 return false; // no children, nothing to revoke.
210 if( mpChild
== rChildLayer
)
212 // we have it - replace by removed child's sibling.
213 mpChild
= rChildLayer
->getChildLayer();
215 // if we're now the first one, defensively increment _all_
216 // state ids: possibly all underlying attributes have now
217 // changed to default
220 // TODO(P1): Check whether it pays off to check more
221 // detailed, which attributes really change
222 ++mnTransformationState
;
232 // we don't have it - pass on the request
233 if( !mpChild
->revokeChildLayer( rChildLayer
) )
234 return false; // nobody has it - bail out
237 // something might have changed - update ids.
243 ShapeAttributeLayerSharedPtr
ShapeAttributeLayer::getChildLayer() const
248 void ShapeAttributeLayer::setAdditiveMode( sal_Int16 nMode
)
250 if( mnAdditiveMode
!= nMode
)
252 // TODO(P1): Check whether it pays off to check more
253 // detailed, which attributes really change
255 // defensively increment all states - possibly each of them
256 // will change with different additive mode
257 ++mnTransformationState
;
265 mnAdditiveMode
= nMode
;
268 bool ShapeAttributeLayer::isWidthValid() const
270 return mbWidthValid
|| (haveChild() && mpChild
->isWidthValid());
273 double ShapeAttributeLayer::getWidth() const
275 return calcValue
< double >(
278 &ShapeAttributeLayer::isWidthValid
,
279 &ShapeAttributeLayer::getWidth
);
282 void ShapeAttributeLayer::setWidth( const double& rNewWidth
)
284 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewWidth
),
285 "ShapeAttributeLayer::setWidth(): Invalid width" );
287 maSize
.setX( rNewWidth
);
289 ++mnTransformationState
;
292 bool ShapeAttributeLayer::isHeightValid() const
294 return mbHeightValid
|| ( haveChild() && mpChild
->isHeightValid() );
297 double ShapeAttributeLayer::getHeight() const
299 return calcValue
< double >(
302 &ShapeAttributeLayer::isHeightValid
,
303 &ShapeAttributeLayer::getHeight
);
306 void ShapeAttributeLayer::setHeight( const double& rNewHeight
)
308 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewHeight
),
309 "ShapeAttributeLayer::setHeight(): Invalid height" );
311 maSize
.setY( rNewHeight
);
312 mbHeightValid
= true;
313 ++mnTransformationState
;
316 void ShapeAttributeLayer::setSize( const ::basegfx::B2DSize
& rNewSize
)
318 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewSize
.getX()) &&
319 ::rtl::math::isFinite(rNewSize
.getY()),
320 "ShapeAttributeLayer::setSize(): Invalid size" );
323 mbWidthValid
= mbHeightValid
= true;
324 ++mnTransformationState
;
327 bool ShapeAttributeLayer::isPosXValid() const
329 return mbPosXValid
|| ( haveChild() && mpChild
->isPosXValid() );
332 double ShapeAttributeLayer::getPosX() const
334 return calcValue
< double >(
337 &ShapeAttributeLayer::isPosXValid
,
338 &ShapeAttributeLayer::getPosX
);
341 void ShapeAttributeLayer::setPosX( const double& rNewX
)
343 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewX
),
344 "ShapeAttributeLayer::setPosX(): Invalid position" );
346 maPosition
.setX( rNewX
);
351 bool ShapeAttributeLayer::isPosYValid() const
353 return mbPosYValid
|| ( haveChild() && mpChild
->isPosYValid() );
356 double ShapeAttributeLayer::getPosY() const
358 return calcValue
< double >(
361 &ShapeAttributeLayer::isPosYValid
,
362 &ShapeAttributeLayer::getPosY
);
365 void ShapeAttributeLayer::setPosY( const double& rNewY
)
367 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewY
),
368 "ShapeAttributeLayer::setPosY(): Invalid position" );
370 maPosition
.setY( rNewY
);
375 void ShapeAttributeLayer::setPosition( const ::basegfx::B2DPoint
& rNewPos
)
377 maPosition
= rNewPos
;
378 mbPosXValid
= mbPosYValid
= true;
382 bool ShapeAttributeLayer::isRotationAngleValid() const
384 return mbRotationAngleValid
|| ( haveChild() && mpChild
->isRotationAngleValid() );
387 double ShapeAttributeLayer::getRotationAngle() const
389 return calcValue
< double >(
391 mbRotationAngleValid
,
392 &ShapeAttributeLayer::isRotationAngleValid
,
393 &ShapeAttributeLayer::getRotationAngle
);
396 void ShapeAttributeLayer::setRotationAngle( const double& rNewAngle
)
398 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
399 "ShapeAttributeLayer::setRotationAngle(): Invalid angle" );
401 mnRotationAngle
= rNewAngle
;
402 mbRotationAngleValid
= true;
403 ++mnTransformationState
;
406 bool ShapeAttributeLayer::isShearXAngleValid() const
408 return mbShearXAngleValid
|| ( haveChild() && mpChild
->isShearXAngleValid() );
411 double ShapeAttributeLayer::getShearXAngle() const
413 return calcValue( mnShearXAngle
,
415 &ShapeAttributeLayer::isShearXAngleValid
,
416 &ShapeAttributeLayer::getShearXAngle
);
419 void ShapeAttributeLayer::setShearXAngle( const double& rNewAngle
)
421 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
422 "ShapeAttributeLayer::setShearXAngle(): Invalid angle" );
424 mnShearXAngle
= rNewAngle
;
425 mbShearXAngleValid
= true;
426 ++mnTransformationState
;
429 bool ShapeAttributeLayer::isShearYAngleValid() const
431 return mbShearYAngleValid
|| ( haveChild() && mpChild
->isShearYAngleValid() );
434 double ShapeAttributeLayer::getShearYAngle() const
436 return calcValue( mnShearYAngle
,
438 &ShapeAttributeLayer::isShearYAngleValid
,
439 &ShapeAttributeLayer::getShearYAngle
);
442 void ShapeAttributeLayer::setShearYAngle( const double& rNewAngle
)
444 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
445 "ShapeAttributeLayer::setShearYAngle(): Invalid angle" );
447 mnShearYAngle
= rNewAngle
;
448 mbShearYAngleValid
= true;
449 ++mnTransformationState
;
452 bool ShapeAttributeLayer::isAlphaValid() const
454 return mbAlphaValid
|| ( haveChild() && mpChild
->isAlphaValid() );
457 double ShapeAttributeLayer::getAlpha() const
459 return calcValue( mnAlpha
,
461 &ShapeAttributeLayer::isAlphaValid
,
462 &ShapeAttributeLayer::getAlpha
);
465 void ShapeAttributeLayer::setAlpha( const double& rNewValue
)
467 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewValue
),
468 "ShapeAttributeLayer::setAlpha(): Invalid alpha" );
475 bool ShapeAttributeLayer::isClipValid() const
477 return mbClipValid
|| ( haveChild() && mpChild
->isClipValid() );
480 ::basegfx::B2DPolyPolygon
ShapeAttributeLayer::getClip() const
482 // TODO(F1): Implement polygon algebra for additive modes
485 else if( haveChild() )
486 return mpChild
->getClip();
488 return ::basegfx::B2DPolyPolygon();
491 void ShapeAttributeLayer::setClip( const ::basegfx::B2DPolyPolygon
& rNewClip
)
498 bool ShapeAttributeLayer::isDimColorValid() const
500 return mbDimColorValid
|| ( haveChild() && mpChild
->isDimColorValid() );
503 RGBColor
ShapeAttributeLayer::getDimColor() const
505 return calcValue( maDimColor
,
507 &ShapeAttributeLayer::isDimColorValid
,
508 &ShapeAttributeLayer::getDimColor
);
511 void ShapeAttributeLayer::setDimColor( const RGBColor
& nNewColor
)
513 maDimColor
= nNewColor
;
514 mbDimColorValid
= true;
518 bool ShapeAttributeLayer::isFillColorValid() const
520 return mbFillColorValid
|| ( haveChild() && mpChild
->isFillColorValid() );
523 RGBColor
ShapeAttributeLayer::getFillColor() const
525 return calcValue( maFillColor
,
527 &ShapeAttributeLayer::isFillColorValid
,
528 &ShapeAttributeLayer::getFillColor
);
531 void ShapeAttributeLayer::setFillColor( const RGBColor
& nNewColor
)
533 maFillColor
= nNewColor
;
534 mbFillColorValid
= true;
538 bool ShapeAttributeLayer::isLineColorValid() const
540 return mbLineColorValid
|| ( haveChild() && mpChild
->isLineColorValid() );
543 RGBColor
ShapeAttributeLayer::getLineColor() const
545 return calcValue( maLineColor
,
547 &ShapeAttributeLayer::isLineColorValid
,
548 &ShapeAttributeLayer::getLineColor
);
551 void ShapeAttributeLayer::setLineColor( const RGBColor
& nNewColor
)
553 maLineColor
= nNewColor
;
554 mbLineColorValid
= true;
558 bool ShapeAttributeLayer::isFillStyleValid() const
560 return mbFillStyleValid
|| ( haveChild() && mpChild
->isFillStyleValid() );
563 sal_Int16
ShapeAttributeLayer::getFillStyle() const
565 // mnAdditiveMode is ignored, cannot combine strings in
567 if( mbFillStyleValid
)
568 return sal::static_int_cast
<sal_Int16
>(meFillStyle
);
569 else if( haveChild() )
570 return sal::static_int_cast
<sal_Int16
>(mpChild
->getFillStyle());
572 return sal::static_int_cast
<sal_Int16
>(drawing::FillStyle_SOLID
);
575 void ShapeAttributeLayer::setFillStyle( const sal_Int16
& rStyle
)
577 // TODO(Q1): Check range here.
578 meFillStyle
= (drawing::FillStyle
)rStyle
;
579 mbFillStyleValid
= true;
583 bool ShapeAttributeLayer::isLineStyleValid() const
585 return mbLineStyleValid
|| ( haveChild() && mpChild
->isLineStyleValid() );
588 sal_Int16
ShapeAttributeLayer::getLineStyle() const
590 // mnAdditiveMode is ignored, cannot combine strings in
592 if( mbLineStyleValid
)
593 return sal::static_int_cast
<sal_Int16
>(meLineStyle
);
594 else if( haveChild() )
595 return sal::static_int_cast
<sal_Int16
>(mpChild
->getLineStyle());
597 return sal::static_int_cast
<sal_Int16
>(drawing::LineStyle_SOLID
);
600 void ShapeAttributeLayer::setLineStyle( const sal_Int16
& rStyle
)
602 // TODO(Q1): Check range here.
603 meLineStyle
= (drawing::LineStyle
)rStyle
;
604 mbLineStyleValid
= true;
608 bool ShapeAttributeLayer::isVisibilityValid() const
610 return mbVisibilityValid
|| ( haveChild() && mpChild
->isVisibilityValid() );
613 bool ShapeAttributeLayer::getVisibility() const
615 // mnAdditiveMode is ignored, SMIL spec requires to not combine
616 // bools in any sensible way
617 if( mbVisibilityValid
)
619 else if( haveChild() )
620 return mpChild
->getVisibility();
622 return true; // default is always visible
625 void ShapeAttributeLayer::setVisibility( const bool& bVisible
)
627 mbVisibility
= bVisible
;
628 mbVisibilityValid
= true;
632 bool ShapeAttributeLayer::isCharColorValid() const
634 return mbCharColorValid
|| ( haveChild() && mpChild
->isCharColorValid() );
637 RGBColor
ShapeAttributeLayer::getCharColor() const
639 return calcValue( maCharColor
,
641 &ShapeAttributeLayer::isCharColorValid
,
642 &ShapeAttributeLayer::getCharColor
);
645 void ShapeAttributeLayer::setCharColor( const RGBColor
& nNewColor
)
647 maCharColor
= nNewColor
;
648 mbCharColorValid
= true;
652 bool ShapeAttributeLayer::isCharRotationAngleValid() const
654 return mbCharRotationAngleValid
|| ( haveChild() && mpChild
->isCharRotationAngleValid() );
657 double ShapeAttributeLayer::getCharRotationAngle() const
659 return calcValue( mnCharRotationAngle
,
660 mbCharRotationAngleValid
,
661 &ShapeAttributeLayer::isCharRotationAngleValid
,
662 &ShapeAttributeLayer::getCharRotationAngle
);
665 void ShapeAttributeLayer::setCharRotationAngle( const double& rNewAngle
)
667 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
668 "ShapeAttributeLayer::setCharRotationAngle(): Invalid angle" );
670 mnCharRotationAngle
= rNewAngle
;
671 mbCharRotationAngleValid
= true;
675 bool ShapeAttributeLayer::isCharWeightValid() const
677 return mbCharWeightValid
|| ( haveChild() && mpChild
->isCharWeightValid() );
680 double ShapeAttributeLayer::getCharWeight() const
682 // mnAdditiveMode is ignored, cannot combine strings in
684 if( mbCharWeightValid
)
686 else if( haveChild() )
687 return mpChild
->getCharWeight();
689 return awt::FontWeight::NORMAL
;
692 void ShapeAttributeLayer::setCharWeight( const double& rValue
)
694 // TODO(Q1): Check range here.
695 mnCharWeight
= rValue
;
696 mbCharWeightValid
= true;
700 bool ShapeAttributeLayer::isUnderlineModeValid() const
702 return mbUnderlineModeValid
|| ( haveChild() && mpChild
->isUnderlineModeValid() );
705 sal_Int16
ShapeAttributeLayer::getUnderlineMode() const
707 // mnAdditiveMode is ignored, SMIL spec requires to not combine
708 // bools in any sensible way
709 if( mbUnderlineModeValid
)
710 return mnUnderlineMode
;
711 else if( haveChild() )
712 return mpChild
->getUnderlineMode();
714 return awt::FontUnderline::NONE
; // default is no underline
717 void ShapeAttributeLayer::setUnderlineMode( const sal_Int16
& rUnderlineMode
)
719 // TODO(Q1): Check range here.
720 mnUnderlineMode
= rUnderlineMode
;
721 mbUnderlineModeValid
= true;
725 bool ShapeAttributeLayer::isFontFamilyValid() const
727 return mbFontFamilyValid
|| ( haveChild() && mpChild
->isFontFamilyValid() );
730 OUString
ShapeAttributeLayer::getFontFamily() const
732 // mnAdditiveMode is ignored, cannot combine strings in
734 if( mbFontFamilyValid
)
736 else if( haveChild() )
737 return mpChild
->getFontFamily();
742 void ShapeAttributeLayer::setFontFamily( const OUString
& rName
)
744 maFontFamily
= rName
;
745 mbFontFamilyValid
= true;
749 bool ShapeAttributeLayer::isCharPostureValid() const
751 return mbCharPostureValid
|| ( haveChild() && mpChild
->isCharPostureValid() );
754 sal_Int16
ShapeAttributeLayer::getCharPosture() const
756 // mnAdditiveMode is ignored, cannot combine strings in
758 if( mbCharPostureValid
)
759 return sal::static_int_cast
<sal_Int16
>(meCharPosture
);
760 else if( haveChild() )
761 return sal::static_int_cast
<sal_Int16
>(mpChild
->getCharPosture());
763 return sal::static_int_cast
<sal_Int16
>(awt::FontSlant_NONE
);
766 void ShapeAttributeLayer::setCharPosture( const sal_Int16
& rStyle
)
768 // TODO(Q1): Check range here.
769 meCharPosture
= (awt::FontSlant
)rStyle
;
770 mbCharPostureValid
= true;
774 bool ShapeAttributeLayer::isCharScaleValid() const
776 return mbCharScaleValid
|| ( haveChild() && mpChild
->isCharScaleValid() );
779 double ShapeAttributeLayer::getCharScale() const
781 return calcValue( mnCharScale
,
783 &ShapeAttributeLayer::isCharScaleValid
,
784 &ShapeAttributeLayer::getCharScale
);
787 void ShapeAttributeLayer::setCharScale( const double& rNewHeight
)
789 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewHeight
),
790 "ShapeAttributeLayer::setCharScale(): Invalid height" );
792 mnCharScale
= rNewHeight
;
793 mbCharScaleValid
= true;
797 State::StateId
ShapeAttributeLayer::getTransformationState() const
800 ::std::max( mnTransformationState
,
801 mpChild
->getTransformationState() ) :
802 mnTransformationState
;
805 State::StateId
ShapeAttributeLayer::getClipState() const
808 ::std::max( mnClipState
,
809 mpChild
->getClipState() ) :
813 State::StateId
ShapeAttributeLayer::getAlphaState() const
816 ::std::max( mnAlphaState
,
817 mpChild
->getAlphaState() ) :
821 State::StateId
ShapeAttributeLayer::getPositionState() const
824 ::std::max( mnPositionState
,
825 mpChild
->getPositionState() ) :
829 State::StateId
ShapeAttributeLayer::getContentState() const
832 ::std::max( mnContentState
,
833 mpChild
->getContentState() ) :
837 State::StateId
ShapeAttributeLayer::getVisibilityState() const
840 ::std::max( mnVisibilityState
,
841 mpChild
->getVisibilityState() ) :
848 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */