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 <tools/diagnose_ex.h>
23 #include <shapeattributelayer.hxx>
25 #include <com/sun/star/awt/Rectangle.hpp>
26 #include <com/sun/star/awt/FontUnderline.hpp>
27 #include <com/sun/star/awt/FontWeight.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/animations/AnimationAdditiveMode.hpp>
31 #include <basegfx/numeric/ftools.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <rtl/math.hxx>
36 using namespace ::com::sun::star
;
45 This method updates all state IDs from possible
46 children. Whenever a child's state ID changed, we
49 void ShapeAttributeLayer::updateStateIds()
53 if( mnTransformationState
!= mpChild
->getTransformationState() )
54 ++mnTransformationState
;
55 if( mnClipState
!= mpChild
->getClipState() )
57 if( mnAlphaState
!= mpChild
->getAlphaState() )
59 if( mnPositionState
!= mpChild
->getPositionState() )
61 if( mnContentState
!= mpChild
->getContentState() )
63 if( mnVisibilityState
!= mpChild
->getVisibilityState() )
68 /** Calc attribute value.
70 This method determines the current attribute value,
71 appropriately combining it with children values (by
72 evaluating the mnAdditiveMode member).
74 template< typename T
> T
ShapeAttributeLayer::calcValue( const T
& rCurrValue
,
75 bool bThisInstanceValid
,
76 bool (ShapeAttributeLayer::*pIsValid
)() const,
77 T (ShapeAttributeLayer::*pGetValue
)() const ) const
79 // deviated from the (*shared_ptr).*mpFuncPtr notation
80 // here, since gcc does not seem to parse that as a member
81 // function call anymore.
82 const bool bChildInstanceValueValid( haveChild() && (mpChild
.get()->*pIsValid
)() );
84 if( bThisInstanceValid
)
86 if( bChildInstanceValueValid
)
88 // merge with child value
89 switch( mnAdditiveMode
)
92 // FALTHROUGH intended
93 case animations::AnimationAdditiveMode::NONE
:
94 // FALTHROUGH intended
95 case animations::AnimationAdditiveMode::BASE
:
96 // FALTHROUGH intended
97 case animations::AnimationAdditiveMode::REPLACE
:
98 // TODO(F2): reverse-engineer the semantics of these
101 // currently, treat them the same and replace
102 // the child value by our own
105 case animations::AnimationAdditiveMode::SUM
:
106 return rCurrValue
+ ((*mpChild
).*pGetValue
)();
108 case animations::AnimationAdditiveMode::MULTIPLY
:
109 return rCurrValue
* ((*mpChild
).*pGetValue
)();
114 // this object is the only one defining
115 // the value, so take it
121 return bChildInstanceValueValid
?
122 ((*mpChild
).*pGetValue
)() :
123 T(); // pass on child value, regardless
124 // if it's valid or not. If not, it's
129 ShapeAttributeLayer::ShapeAttributeLayer( const ShapeAttributeLayerSharedPtr
& rChildLayer
) :
130 mpChild( rChildLayer
),
142 mnCharRotationAngle(),
146 meFillStyle( drawing::FillStyle_NONE
),
147 meLineStyle( drawing::LineStyle_NONE
),
148 meCharPosture( awt::FontSlant_NONE
),
156 mnTransformationState( rChildLayer
? rChildLayer
->getTransformationState() : 0 ),
157 mnClipState( rChildLayer
? rChildLayer
->getClipState() : 0),
158 mnAlphaState( rChildLayer
? rChildLayer
->getAlphaState() : 0),
159 mnPositionState( rChildLayer
? rChildLayer
->getPositionState() : 0 ),
160 mnContentState( rChildLayer
? rChildLayer
->getContentState() : 0 ),
161 mnVisibilityState( rChildLayer
? rChildLayer
->getVisibilityState() : 0 ),
163 mnAdditiveMode( animations::AnimationAdditiveMode::BASE
),
165 mbVisibility( false ),
167 mbWidthValid( false ),
168 mbHeightValid( false ),
169 mbPosXValid( false ),
170 mbPosYValid( false ),
171 mbClipValid( false ),
173 mbFontFamilyValid( false ),
175 mbRotationAngleValid( false ),
176 mbShearXAngleValid( false ),
177 mbShearYAngleValid( false ),
179 mbAlphaValid( false ),
181 mbCharRotationAngleValid( false ),
182 mbCharScaleValid( false ),
184 mbDimColorValid( false ),
185 mbFillColorValid( false ),
186 mbLineColorValid( false ),
187 mbCharColorValid( false ),
189 mbFillStyleValid( false ),
190 mbLineStyleValid( false ),
191 mbCharWeightValid( false ),
192 mbUnderlineModeValid( false ),
193 mbCharPostureValid( false ),
194 mbVisibilityValid( false )
198 bool ShapeAttributeLayer::revokeChildLayer( const ShapeAttributeLayerSharedPtr
& rChildLayer
)
200 ENSURE_OR_RETURN_FALSE( rChildLayer
,
201 "ShapeAttributeLayer::revokeChildLayer(): Will not remove NULL child" );
204 return false; // no children, nothing to revoke.
206 if( mpChild
== rChildLayer
)
208 // we have it - replace by removed child's sibling.
209 mpChild
= rChildLayer
->getChildLayer();
211 // if we're now the first one, defensively increment _all_
212 // state ids: possibly all underlying attributes have now
213 // changed to default
216 // TODO(P1): Check whether it pays off to check more
217 // detailed, which attributes really change
218 ++mnTransformationState
;
228 // we don't have it - pass on the request
229 if( !mpChild
->revokeChildLayer( rChildLayer
) )
230 return false; // nobody has it - bail out
233 // something might have changed - update ids.
239 const ShapeAttributeLayerSharedPtr
& ShapeAttributeLayer::getChildLayer() const
244 void ShapeAttributeLayer::setAdditiveMode( sal_Int16 nMode
)
246 if( mnAdditiveMode
!= nMode
)
248 // TODO(P1): Check whether it pays off to check more
249 // detailed, which attributes really change
251 // defensively increment all states - possibly each of them
252 // will change with different additive mode
253 ++mnTransformationState
;
261 mnAdditiveMode
= nMode
;
264 bool ShapeAttributeLayer::isWidthValid() const
266 return mbWidthValid
|| (haveChild() && mpChild
->isWidthValid());
269 double ShapeAttributeLayer::getWidth() const
271 return calcValue
< double >(
274 &ShapeAttributeLayer::isWidthValid
,
275 &ShapeAttributeLayer::getWidth
);
278 void ShapeAttributeLayer::setWidth( const double& rNewWidth
)
280 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewWidth
),
281 "ShapeAttributeLayer::setWidth(): Invalid width" );
283 maSize
.setX( rNewWidth
);
285 ++mnTransformationState
;
288 bool ShapeAttributeLayer::isHeightValid() const
290 return mbHeightValid
|| ( haveChild() && mpChild
->isHeightValid() );
293 double ShapeAttributeLayer::getHeight() const
295 return calcValue
< double >(
298 &ShapeAttributeLayer::isHeightValid
,
299 &ShapeAttributeLayer::getHeight
);
302 void ShapeAttributeLayer::setHeight( const double& rNewHeight
)
304 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewHeight
),
305 "ShapeAttributeLayer::setHeight(): Invalid height" );
307 maSize
.setY( rNewHeight
);
308 mbHeightValid
= true;
309 ++mnTransformationState
;
312 void ShapeAttributeLayer::setSize( const ::basegfx::B2DSize
& rNewSize
)
314 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewSize
.getX()) &&
315 ::rtl::math::isFinite(rNewSize
.getY()),
316 "ShapeAttributeLayer::setSize(): Invalid size" );
319 mbWidthValid
= mbHeightValid
= true;
320 ++mnTransformationState
;
323 bool ShapeAttributeLayer::isPosXValid() const
325 return mbPosXValid
|| ( haveChild() && mpChild
->isPosXValid() );
328 double ShapeAttributeLayer::getPosX() const
330 return calcValue
< double >(
333 &ShapeAttributeLayer::isPosXValid
,
334 &ShapeAttributeLayer::getPosX
);
337 void ShapeAttributeLayer::setPosX( const double& rNewX
)
339 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewX
),
340 "ShapeAttributeLayer::setPosX(): Invalid position" );
342 maPosition
.setX( rNewX
);
347 bool ShapeAttributeLayer::isPosYValid() const
349 return mbPosYValid
|| ( haveChild() && mpChild
->isPosYValid() );
352 double ShapeAttributeLayer::getPosY() const
354 return calcValue
< double >(
357 &ShapeAttributeLayer::isPosYValid
,
358 &ShapeAttributeLayer::getPosY
);
361 void ShapeAttributeLayer::setPosY( const double& rNewY
)
363 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewY
),
364 "ShapeAttributeLayer::setPosY(): Invalid position" );
366 maPosition
.setY( rNewY
);
371 void ShapeAttributeLayer::setPosition( const ::basegfx::B2DPoint
& rNewPos
)
373 maPosition
= rNewPos
;
374 mbPosXValid
= mbPosYValid
= true;
378 bool ShapeAttributeLayer::isRotationAngleValid() const
380 return mbRotationAngleValid
|| ( haveChild() && mpChild
->isRotationAngleValid() );
383 double ShapeAttributeLayer::getRotationAngle() const
385 return calcValue
< double >(
387 mbRotationAngleValid
,
388 &ShapeAttributeLayer::isRotationAngleValid
,
389 &ShapeAttributeLayer::getRotationAngle
);
392 void ShapeAttributeLayer::setRotationAngle( const double& rNewAngle
)
394 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
395 "ShapeAttributeLayer::setRotationAngle(): Invalid angle" );
397 mnRotationAngle
= rNewAngle
;
398 mbRotationAngleValid
= true;
399 ++mnTransformationState
;
402 bool ShapeAttributeLayer::isShearXAngleValid() const
404 return mbShearXAngleValid
|| ( haveChild() && mpChild
->isShearXAngleValid() );
407 double ShapeAttributeLayer::getShearXAngle() const
409 return calcValue( mnShearXAngle
,
411 &ShapeAttributeLayer::isShearXAngleValid
,
412 &ShapeAttributeLayer::getShearXAngle
);
415 void ShapeAttributeLayer::setShearXAngle( const double& rNewAngle
)
417 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
418 "ShapeAttributeLayer::setShearXAngle(): Invalid angle" );
420 mnShearXAngle
= rNewAngle
;
421 mbShearXAngleValid
= true;
422 ++mnTransformationState
;
425 bool ShapeAttributeLayer::isShearYAngleValid() const
427 return mbShearYAngleValid
|| ( haveChild() && mpChild
->isShearYAngleValid() );
430 double ShapeAttributeLayer::getShearYAngle() const
432 return calcValue( mnShearYAngle
,
434 &ShapeAttributeLayer::isShearYAngleValid
,
435 &ShapeAttributeLayer::getShearYAngle
);
438 void ShapeAttributeLayer::setShearYAngle( const double& rNewAngle
)
440 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
441 "ShapeAttributeLayer::setShearYAngle(): Invalid angle" );
443 mnShearYAngle
= rNewAngle
;
444 mbShearYAngleValid
= true;
445 ++mnTransformationState
;
448 bool ShapeAttributeLayer::isAlphaValid() const
450 return mbAlphaValid
|| ( haveChild() && mpChild
->isAlphaValid() );
453 double ShapeAttributeLayer::getAlpha() const
455 return calcValue( mnAlpha
,
457 &ShapeAttributeLayer::isAlphaValid
,
458 &ShapeAttributeLayer::getAlpha
);
461 void ShapeAttributeLayer::setAlpha( const double& rNewValue
)
463 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewValue
),
464 "ShapeAttributeLayer::setAlpha(): Invalid alpha" );
471 bool ShapeAttributeLayer::isClipValid() const
473 return mbClipValid
|| ( haveChild() && mpChild
->isClipValid() );
476 ::basegfx::B2DPolyPolygon
ShapeAttributeLayer::getClip() const
478 // TODO(F1): Implement polygon algebra for additive modes
481 else if( haveChild() )
482 return mpChild
->getClip();
484 return ::basegfx::B2DPolyPolygon();
487 void ShapeAttributeLayer::setClip( const ::basegfx::B2DPolyPolygon
& rNewClip
)
494 bool ShapeAttributeLayer::isDimColorValid() const
496 return mbDimColorValid
|| ( haveChild() && mpChild
->isDimColorValid() );
499 RGBColor
ShapeAttributeLayer::getDimColor() const
501 return calcValue( maDimColor
,
503 &ShapeAttributeLayer::isDimColorValid
,
504 &ShapeAttributeLayer::getDimColor
);
507 void ShapeAttributeLayer::setDimColor( const RGBColor
& nNewColor
)
509 maDimColor
= nNewColor
;
510 mbDimColorValid
= true;
514 bool ShapeAttributeLayer::isFillColorValid() const
516 return mbFillColorValid
|| ( haveChild() && mpChild
->isFillColorValid() );
519 RGBColor
ShapeAttributeLayer::getFillColor() const
521 return calcValue( maFillColor
,
523 &ShapeAttributeLayer::isFillColorValid
,
524 &ShapeAttributeLayer::getFillColor
);
527 void ShapeAttributeLayer::setFillColor( const RGBColor
& nNewColor
)
529 maFillColor
= nNewColor
;
530 mbFillColorValid
= true;
534 bool ShapeAttributeLayer::isLineColorValid() const
536 return mbLineColorValid
|| ( haveChild() && mpChild
->isLineColorValid() );
539 RGBColor
ShapeAttributeLayer::getLineColor() const
541 return calcValue( maLineColor
,
543 &ShapeAttributeLayer::isLineColorValid
,
544 &ShapeAttributeLayer::getLineColor
);
547 void ShapeAttributeLayer::setLineColor( const RGBColor
& nNewColor
)
549 maLineColor
= nNewColor
;
550 mbLineColorValid
= true;
554 bool ShapeAttributeLayer::isFillStyleValid() const
556 return mbFillStyleValid
|| ( haveChild() && mpChild
->isFillStyleValid() );
559 sal_Int16
ShapeAttributeLayer::getFillStyle() const
561 // mnAdditiveMode is ignored, cannot combine strings in
563 if( mbFillStyleValid
)
564 return sal::static_int_cast
<sal_Int16
>(meFillStyle
);
565 else if( haveChild() )
566 return sal::static_int_cast
<sal_Int16
>(mpChild
->getFillStyle());
568 return sal::static_int_cast
<sal_Int16
>(drawing::FillStyle_SOLID
);
571 void ShapeAttributeLayer::setFillStyle( const sal_Int16
& rStyle
)
573 // TODO(Q1): Check range here.
574 meFillStyle
= (drawing::FillStyle
)rStyle
;
575 mbFillStyleValid
= true;
579 bool ShapeAttributeLayer::isLineStyleValid() const
581 return mbLineStyleValid
|| ( haveChild() && mpChild
->isLineStyleValid() );
584 sal_Int16
ShapeAttributeLayer::getLineStyle() const
586 // mnAdditiveMode is ignored, cannot combine strings in
588 if( mbLineStyleValid
)
589 return sal::static_int_cast
<sal_Int16
>(meLineStyle
);
590 else if( haveChild() )
591 return sal::static_int_cast
<sal_Int16
>(mpChild
->getLineStyle());
593 return sal::static_int_cast
<sal_Int16
>(drawing::LineStyle_SOLID
);
596 void ShapeAttributeLayer::setLineStyle( const sal_Int16
& rStyle
)
598 // TODO(Q1): Check range here.
599 meLineStyle
= (drawing::LineStyle
)rStyle
;
600 mbLineStyleValid
= true;
604 bool ShapeAttributeLayer::isVisibilityValid() const
606 return mbVisibilityValid
|| ( haveChild() && mpChild
->isVisibilityValid() );
609 bool ShapeAttributeLayer::getVisibility() const
611 // mnAdditiveMode is ignored, SMIL spec requires to not combine
612 // bools in any sensible way
613 if( mbVisibilityValid
)
615 else if( haveChild() )
616 return mpChild
->getVisibility();
618 return true; // default is always visible
621 void ShapeAttributeLayer::setVisibility( const bool& bVisible
)
623 mbVisibility
= bVisible
;
624 mbVisibilityValid
= true;
628 bool ShapeAttributeLayer::isCharColorValid() const
630 return mbCharColorValid
|| ( haveChild() && mpChild
->isCharColorValid() );
633 RGBColor
ShapeAttributeLayer::getCharColor() const
635 return calcValue( maCharColor
,
637 &ShapeAttributeLayer::isCharColorValid
,
638 &ShapeAttributeLayer::getCharColor
);
641 void ShapeAttributeLayer::setCharColor( const RGBColor
& nNewColor
)
643 maCharColor
= nNewColor
;
644 mbCharColorValid
= true;
648 bool ShapeAttributeLayer::isCharRotationAngleValid() const
650 return mbCharRotationAngleValid
|| ( haveChild() && mpChild
->isCharRotationAngleValid() );
653 double ShapeAttributeLayer::getCharRotationAngle() const
655 return calcValue( mnCharRotationAngle
,
656 mbCharRotationAngleValid
,
657 &ShapeAttributeLayer::isCharRotationAngleValid
,
658 &ShapeAttributeLayer::getCharRotationAngle
);
661 void ShapeAttributeLayer::setCharRotationAngle( const double& rNewAngle
)
663 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle
),
664 "ShapeAttributeLayer::setCharRotationAngle(): Invalid angle" );
666 mnCharRotationAngle
= rNewAngle
;
667 mbCharRotationAngleValid
= true;
671 bool ShapeAttributeLayer::isCharWeightValid() const
673 return mbCharWeightValid
|| ( haveChild() && mpChild
->isCharWeightValid() );
676 double ShapeAttributeLayer::getCharWeight() const
678 // mnAdditiveMode is ignored, cannot combine strings in
680 if( mbCharWeightValid
)
682 else if( haveChild() )
683 return mpChild
->getCharWeight();
685 return awt::FontWeight::NORMAL
;
688 void ShapeAttributeLayer::setCharWeight( const double& rValue
)
690 // TODO(Q1): Check range here.
691 mnCharWeight
= rValue
;
692 mbCharWeightValid
= true;
696 bool ShapeAttributeLayer::isUnderlineModeValid() const
698 return mbUnderlineModeValid
|| ( haveChild() && mpChild
->isUnderlineModeValid() );
701 sal_Int16
ShapeAttributeLayer::getUnderlineMode() const
703 // mnAdditiveMode is ignored, SMIL spec requires to not combine
704 // bools in any sensible way
705 if( mbUnderlineModeValid
)
706 return mnUnderlineMode
;
707 else if( haveChild() )
708 return mpChild
->getUnderlineMode();
710 return awt::FontUnderline::NONE
; // default is no underline
713 void ShapeAttributeLayer::setUnderlineMode( const sal_Int16
& rUnderlineMode
)
715 // TODO(Q1): Check range here.
716 mnUnderlineMode
= rUnderlineMode
;
717 mbUnderlineModeValid
= true;
721 bool ShapeAttributeLayer::isFontFamilyValid() const
723 return mbFontFamilyValid
|| ( haveChild() && mpChild
->isFontFamilyValid() );
726 OUString
ShapeAttributeLayer::getFontFamily() const
728 // mnAdditiveMode is ignored, cannot combine strings in
730 if( mbFontFamilyValid
)
732 else if( haveChild() )
733 return mpChild
->getFontFamily();
738 void ShapeAttributeLayer::setFontFamily( const OUString
& rName
)
740 maFontFamily
= rName
;
741 mbFontFamilyValid
= true;
745 bool ShapeAttributeLayer::isCharPostureValid() const
747 return mbCharPostureValid
|| ( haveChild() && mpChild
->isCharPostureValid() );
750 sal_Int16
ShapeAttributeLayer::getCharPosture() const
752 // mnAdditiveMode is ignored, cannot combine strings in
754 if( mbCharPostureValid
)
755 return sal::static_int_cast
<sal_Int16
>(meCharPosture
);
756 else if( haveChild() )
757 return sal::static_int_cast
<sal_Int16
>(mpChild
->getCharPosture());
759 return sal::static_int_cast
<sal_Int16
>(awt::FontSlant_NONE
);
762 void ShapeAttributeLayer::setCharPosture( const sal_Int16
& rStyle
)
764 // TODO(Q1): Check range here.
765 meCharPosture
= (awt::FontSlant
)rStyle
;
766 mbCharPostureValid
= true;
770 bool ShapeAttributeLayer::isCharScaleValid() const
772 return mbCharScaleValid
|| ( haveChild() && mpChild
->isCharScaleValid() );
775 double ShapeAttributeLayer::getCharScale() const
777 return calcValue( mnCharScale
,
779 &ShapeAttributeLayer::isCharScaleValid
,
780 &ShapeAttributeLayer::getCharScale
);
783 void ShapeAttributeLayer::setCharScale( const double& rNewHeight
)
785 ENSURE_OR_THROW( ::rtl::math::isFinite(rNewHeight
),
786 "ShapeAttributeLayer::setCharScale(): Invalid height" );
788 mnCharScale
= rNewHeight
;
789 mbCharScaleValid
= true;
793 State::StateId
ShapeAttributeLayer::getTransformationState() const
796 ::std::max( mnTransformationState
,
797 mpChild
->getTransformationState() ) :
798 mnTransformationState
;
801 State::StateId
ShapeAttributeLayer::getClipState() const
804 ::std::max( mnClipState
,
805 mpChild
->getClipState() ) :
809 State::StateId
ShapeAttributeLayer::getAlphaState() const
812 ::std::max( mnAlphaState
,
813 mpChild
->getAlphaState() ) :
817 State::StateId
ShapeAttributeLayer::getPositionState() const
820 ::std::max( mnPositionState
,
821 mpChild
->getPositionState() ) :
825 State::StateId
ShapeAttributeLayer::getContentState() const
828 ::std::max( mnContentState
,
829 mpChild
->getContentState() ) :
833 State::StateId
ShapeAttributeLayer::getVisibilityState() const
836 ::std::max( mnVisibilityState
,
837 mpChild
->getVisibilityState() ) :
844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */