From 2a7ab2ab7786ab88b1bdbbe5e4b00ea8e93636f7 Mon Sep 17 00:00:00 2001 From: Tomaž Vajngerl Date: Thu, 2 Mar 2023 23:36:38 +0900 Subject: oox: add model::EffectStyle and import effect style elements of a theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the SwCoreThemeTest with effect style use-cases- Change-Id: Ifcb96a860fcbc0aae65e8ec276e069f7f60fb950 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149361 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl --- include/docmodel/theme/FormatScheme.hxx | 52 +++++++++++ include/oox/drawingml/drawingmltypes.hxx | 1 + oox/inc/drawingml/effectpropertiescontext.hxx | 7 +- oox/source/drawingml/drawingmltypes.cxx | 20 +++++ oox/source/drawingml/effectpropertiescontext.cxx | 105 ++++++++++++++++++++--- oox/source/drawingml/misccontexts.cxx | 14 +-- oox/source/drawingml/themeelementscontext.cxx | 24 ++++-- sw/qa/core/theme/ThemeTest.cxx | 43 ++++++++++ 8 files changed, 232 insertions(+), 34 deletions(-) diff --git a/include/docmodel/theme/FormatScheme.hxx b/include/docmodel/theme/FormatScheme.hxx index 5d16b79b6231..e207d9935432 100644 --- a/include/docmodel/theme/FormatScheme.hxx +++ b/include/docmodel/theme/FormatScheme.hxx @@ -295,6 +295,7 @@ enum class FlipMode enum class RectangleAlignment { + Unset, TopLeft, Top, TopRight, @@ -465,12 +466,53 @@ public: FillStyle maLineFillStyle; }; +enum class EffectType +{ + Unset, + OuterShadow, + InnerShadow, + Glow, + SoftEdge, + Reflection, + Blur +}; + +class DOCMODEL_DLLPUBLIC Effect +{ +public: + EffectType meType = EffectType::Unset; + sal_Int32 mnBlurRadius = 0; + sal_Int32 mnRadius = 0; + sal_Int32 mnDistance = 0; + sal_Int32 mnDirection = 0; + sal_Int32 mnScaleX = 100; + sal_Int32 mnScaley = 100; + sal_Int32 mnScewX = 0; + sal_Int32 mnScewY = 0; + RectangleAlignment meAlignment = RectangleAlignment::Bottom; + bool mbRotateWithShape = true; + ColorDefinition maColor; + double mnEndAlpha = 100.0; + double mnEndPosition = 0.0; + double mnStartAlpha = 0.0; + double mnStartPosition = 100.0; + sal_Int32 mnFadeDirection = 0; + bool mbGrow = false; +}; + +class DOCMODEL_DLLPUBLIC EffectStyle +{ +public: + std::vector maEffectList; +}; + class DOCMODEL_DLLPUBLIC FormatScheme { private: OUString maName; std::vector maFillStyleList; std::vector maLineStyleList; + std::vector maEffectStyleList; std::vector maBackgroundFillStyleList; public: @@ -493,6 +535,16 @@ public: return &rLineStyle; } + std::vector const& getEffectStyleList() const { return maEffectStyleList; } + + EffectStyle* addEffectStyle() + { + if (maEffectStyleList.size() > 3) + return nullptr; + auto& rEffectStyle = maEffectStyleList.emplace_back(); + return &rEffectStyle; + } + std::vector const& getFillStyleList() const { return maFillStyleList; } FillStyle* addFillStyle() diff --git a/include/oox/drawingml/drawingmltypes.hxx b/include/oox/drawingml/drawingmltypes.hxx index 8dd5dee727d4..239d3283e55c 100644 --- a/include/oox/drawingml/drawingmltypes.hxx +++ b/include/oox/drawingml/drawingmltypes.hxx @@ -231,6 +231,7 @@ struct EmuRectangle : public EmuPoint, public EmuSize void setSize( const EmuSize& rSize ) { static_cast< EmuSize& >( *this ) = rSize; } }; +model::RectangleAlignment convertToRectangleAlignment(sal_Int32 nToken); } // namespace oox::drawingml diff --git a/oox/inc/drawingml/effectpropertiescontext.hxx b/oox/inc/drawingml/effectpropertiescontext.hxx index d6a931043367..81d765cb887a 100644 --- a/oox/inc/drawingml/effectpropertiescontext.hxx +++ b/oox/inc/drawingml/effectpropertiescontext.hxx @@ -11,6 +11,8 @@ #include +namespace model { class EffectStyle; } + namespace oox::drawingml { struct EffectProperties; @@ -19,8 +21,8 @@ struct Effect; class EffectPropertiesContext final : public ::oox::core::ContextHandler2 { public: - EffectPropertiesContext( ::oox::core::ContextHandler2Helper const & rParent, - EffectProperties& rEffectProperties ) noexcept; + EffectPropertiesContext(::oox::core::ContextHandler2Helper const & rParent, EffectProperties& rEffectProperties, + model::EffectStyle* pEffectStyle = nullptr) noexcept; virtual ~EffectPropertiesContext() override; virtual ::oox::core::ContextHandlerRef @@ -29,6 +31,7 @@ public: private: static void saveUnsupportedAttribs( Effect& rEffect, const AttributeList& rAttribs ); + model::EffectStyle* mpEffectStyle; EffectProperties& mrEffectProperties; }; diff --git a/oox/source/drawingml/drawingmltypes.cxx b/oox/source/drawingml/drawingmltypes.cxx index d0bf1bf2c892..469029f48071 100644 --- a/oox/source/drawingml/drawingmltypes.cxx +++ b/oox/source/drawingml/drawingmltypes.cxx @@ -422,6 +422,26 @@ IndexRange GetIndexRange( const Reference< XFastAttributeList >& xAttributes ) return range; } + +model::RectangleAlignment convertToRectangleAlignment(sal_Int32 nToken) +{ + switch (nToken) + { + case XML_tl: return model::RectangleAlignment::TopLeft; + case XML_t: return model::RectangleAlignment::Top; + case XML_tr: return model::RectangleAlignment::TopRight; + case XML_l: return model::RectangleAlignment::Left; + case XML_ctr: return model::RectangleAlignment::Center; + case XML_r: return model::RectangleAlignment::Right; + case XML_bl: return model::RectangleAlignment::BottomLeft; + case XML_b: return model::RectangleAlignment::Bottom; + case XML_br: return model::RectangleAlignment::BottomRight; + default: + break; + } + return model::RectangleAlignment::Unset; +} + } // namespace oox::drawingml /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/effectpropertiescontext.cxx b/oox/source/drawingml/effectpropertiescontext.cxx index 23793cdc26dc..c8c5096829ff 100644 --- a/oox/source/drawingml/effectpropertiescontext.cxx +++ b/oox/source/drawingml/effectpropertiescontext.cxx @@ -13,6 +13,7 @@ #include #include #include +#include using namespace ::oox::core; using namespace ::com::sun::star::uno; @@ -23,9 +24,10 @@ using namespace ::com::sun::star::xml::sax; namespace oox::drawingml { EffectPropertiesContext::EffectPropertiesContext( ContextHandler2Helper const& rParent, - EffectProperties& rEffectProperties ) noexcept -: ContextHandler2( rParent ) -, mrEffectProperties( rEffectProperties ) + EffectProperties& rEffectProperties, model::EffectStyle* pEffectStyle) noexcept + : ContextHandler2(rParent) + , mpEffectStyle(pEffectStyle) + , mrEffectProperties(rEffectProperties) { } @@ -85,7 +87,25 @@ ContextHandlerRef EffectPropertiesContext::onCreateContext( sal_Int32 nElement, mrEffectProperties.maShadow.moShadowSx = rAttribs.getInteger( XML_sx, 0 ); mrEffectProperties.maShadow.moShadowSy = rAttribs.getInteger( XML_sy, 0 ); mrEffectProperties.maShadow.moShadowBlur = rAttribs.getInteger( XML_blurRad, 0 ); - return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor); + + model::ColorDefinition* pColor = nullptr; + if (mpEffectStyle) + { + auto& rEffect = mpEffectStyle->maEffectList.emplace_back(); + rEffect.meType = model::EffectType::OuterShadow; + rEffect.mnBlurRadius = rAttribs.getInteger(XML_blurRad, 0); // ST_PositiveCoordinate, default 0 + rEffect.mnDistance = rAttribs.getInteger(XML_dist, 0); // ST_PositiveCoordinate, default 0 + rEffect.mnDirection = rAttribs.getInteger(XML_dir, 0); // ST_PositiveFixedAngle, default 0 + rEffect.mnScaleX = GetPercent( rAttribs.getStringDefaulted(XML_sx)); // ST_Percentage, default 100% + rEffect.mnScaley = GetPercent( rAttribs.getStringDefaulted(XML_sy)); // ST_Percentage, default 100% + rEffect.mnScewX = rAttribs.getInteger(XML_kx, 0); // ST_FixedAngle, default 0 + rEffect.mnScewY = rAttribs.getInteger(XML_ky, 0); // ST_FixedAngle, default 0 + // ST_RectAlignment, default "b" - Bottom + rEffect.meAlignment = convertToRectangleAlignment(rAttribs.getToken(XML_algn, XML_b)); + rEffect.mbRotateWithShape = rAttribs.getBool(XML_rotWithShape, true); // boolean, default "true" + pColor = &rEffect.maColor; + } + return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor, pColor); } break; case A_TOKEN( innerShdw ): @@ -95,7 +115,18 @@ ContextHandlerRef EffectPropertiesContext::onCreateContext( sal_Int32 nElement, mrEffectProperties.maShadow.moShadowDist = rAttribs.getInteger( XML_dist, 0 ); mrEffectProperties.maShadow.moShadowDir = rAttribs.getInteger( XML_dir, 0 ); - return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor); + + model::ColorDefinition* pColor = nullptr; + if (mpEffectStyle) + { + auto& rEffect = mpEffectStyle->maEffectList.emplace_back(); + rEffect.meType = model::EffectType::InnerShadow; + rEffect.mnBlurRadius = rAttribs.getInteger(XML_blurRad, 0); // ST_PositiveCoordinate, default 0 + rEffect.mnDistance = rAttribs.getInteger(XML_dist, 0); // ST_PositiveCoordinate, default 0 + rEffect.mnDirection = rAttribs.getInteger(XML_dir, 0); // ST_PositiveFixedAngle, default 0 + pColor = &rEffect.maColor; + } + return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor, pColor); } break; case A_TOKEN( glow ): @@ -103,23 +134,75 @@ ContextHandlerRef EffectPropertiesContext::onCreateContext( sal_Int32 nElement, mrEffectProperties.maGlow.moGlowRad = rAttribs.getInteger( XML_rad, 0 ); // undo push_back to effects mrEffectProperties.m_Effects.pop_back(); - return new ColorContext(*this, mrEffectProperties.maGlow.moGlowColor); + + model::ColorDefinition* pColor = nullptr; + if (mpEffectStyle) + { + auto& rEffect = mpEffectStyle->maEffectList.emplace_back(); + rEffect.meType = model::EffectType::Glow; + rEffect.mnRadius = rAttribs.getInteger(XML_rad, 0); //ST_PositiveCoordinate, default 0 + pColor = &rEffect.maColor; + } + return new ColorContext(*this, mrEffectProperties.maGlow.moGlowColor, pColor); } case A_TOKEN( softEdge ): { mrEffectProperties.maSoftEdge.moRad = rAttribs.getInteger(XML_rad, 0); + if (mpEffectStyle) + { + auto& rEffect = mpEffectStyle->maEffectList.emplace_back(); + rEffect.meType = model::EffectType::SoftEdge; + rEffect.mnRadius = rAttribs.getInteger(XML_rad, 0); // ST_PositiveCoordinate, default 0 + } return this; // no inner elements } case A_TOKEN( reflection ): + { + mrEffectProperties.m_Effects[nPos]->msName = "reflection"; + saveUnsupportedAttribs(*mrEffectProperties.m_Effects[nPos], rAttribs); + + model::ColorDefinition* pColor = nullptr; + if (mpEffectStyle) + { + auto& rEffect = mpEffectStyle->maEffectList.emplace_back(); + rEffect.meType = model::EffectType::Reflection; + rEffect.mnBlurRadius = rAttribs.getInteger(XML_blurRad, 0); // ST_PositiveCoordinate, default 0 + rEffect.mnDistance = rAttribs.getInteger(XML_dist, 0); // ST_PositiveCoordinate, default 0 + rEffect.mnDirection = rAttribs.getInteger(XML_dir, 0); // ST_PositiveFixedAngle, default 0 + rEffect.mnScaleX = GetPercent(rAttribs.getStringDefaulted(XML_sx)); // ST_Percentage, default 100% + rEffect.mnScaley = GetPercent(rAttribs.getStringDefaulted(XML_sy)); // ST_Percentage, default 100% + rEffect.mnScewX = rAttribs.getInteger(XML_kx, 0); // ST_FixedAngle, default 0 + rEffect.mnScewY = rAttribs.getInteger(XML_ky, 0); // ST_FixedAngle, default 0 + // ST_RectAlignment, default "b" - Bottom + rEffect.meAlignment = convertToRectangleAlignment(rAttribs.getToken(XML_algn, XML_b)); + rEffect.mbRotateWithShape = rAttribs.getBool(XML_rotWithShape, true); // boolean, default "true" + + rEffect.mnEndAlpha = GetPositiveFixedPercentage(rAttribs.getStringDefaulted(XML_endA)); // ST_PositiveFixedPercentage, default 100% + rEffect.mnEndPosition = GetPositiveFixedPercentage(rAttribs.getStringDefaulted(XML_endPos)); // ST_PositiveFixedPercentage, default 0% + rEffect.mnStartAlpha = GetPositiveFixedPercentage(rAttribs.getStringDefaulted(XML_stA)); // ST_PositiveFixedPercentage, default 0% + rEffect.mnStartPosition = GetPositiveFixedPercentage(rAttribs.getStringDefaulted(XML_stPos)); // ST_PositiveFixedPercentage, default 100% + rEffect.mnFadeDirection = rAttribs.getInteger(XML_fadeDir, 5400000); // ST_PositiveFixedAngle, default 5400000 + + pColor = &rEffect.maColor; + } + return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor, pColor); + } case A_TOKEN( blur ): { - if (nElement == A_TOKEN(reflection)) - mrEffectProperties.m_Effects[nPos]->msName = "reflection"; - else if( nElement == A_TOKEN( blur ) ) - mrEffectProperties.m_Effects[nPos]->msName = "blur"; + mrEffectProperties.m_Effects[nPos]->msName = "blur"; saveUnsupportedAttribs(*mrEffectProperties.m_Effects[nPos], rAttribs); - return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor); + + model::ColorDefinition* pColor = nullptr; + if (mpEffectStyle) + { + auto& rEffect = mpEffectStyle->maEffectList.emplace_back(); + rEffect.meType = model::EffectType::Blur; + rEffect.mnRadius = rAttribs.getInteger(XML_rad, 0); // ST_PositiveCoordinate, default 0 + rEffect.mbGrow = rAttribs.getBool(XML_grow, true); // boolean, default true + pColor = &rEffect.maColor; + } + return new ColorContext(*this, mrEffectProperties.m_Effects[nPos]->moColor, pColor); } break; } diff --git a/oox/source/drawingml/misccontexts.cxx b/oox/source/drawingml/misccontexts.cxx index 3005974bdf37..bf3ec6e4fb03 100644 --- a/oox/source/drawingml/misccontexts.cxx +++ b/oox/source/drawingml/misccontexts.cxx @@ -447,19 +447,7 @@ ContextHandlerRef BlipFillContext::onCreateContext( default: case XML_none: mpBlipFill->meTileFlipMode = model::FlipMode::None; break; } - switch (rAttribs.getToken(XML_algn, XML_tl)) - { - default: - case XML_tl: mpBlipFill->meTileAlignment = model::RectangleAlignment::TopLeft; break; - case XML_t: mpBlipFill->meTileAlignment = model::RectangleAlignment::Top; break; - case XML_tr: mpBlipFill->meTileAlignment = model::RectangleAlignment::TopRight; break; - case XML_l: mpBlipFill->meTileAlignment = model::RectangleAlignment::Left; break; - case XML_ctr: mpBlipFill->meTileAlignment = model::RectangleAlignment::Center; break; - case XML_r: mpBlipFill->meTileAlignment = model::RectangleAlignment::Right; break; - case XML_bl: mpBlipFill->meTileAlignment = model::RectangleAlignment::BottomLeft; break; - case XML_b: mpBlipFill->meTileAlignment = model::RectangleAlignment::Bottom; break; - case XML_br: mpBlipFill->meTileAlignment = model::RectangleAlignment::BottomRight; break; - } + mpBlipFill->meTileAlignment = convertToRectangleAlignment(rAttribs.getToken(XML_algn, XML_TOKEN_INVALID)); } } break; diff --git a/oox/source/drawingml/themeelementscontext.cxx b/oox/source/drawingml/themeelementscontext.cxx index c3230d66039f..c0b8eaed4d78 100644 --- a/oox/source/drawingml/themeelementscontext.cxx +++ b/oox/source/drawingml/themeelementscontext.cxx @@ -142,18 +142,22 @@ namespace { class EffectStyleListContext : public ContextHandler2 { public: - EffectStyleListContext( ContextHandler2Helper const & rParent, EffectStyleList& rEffectStyleList ); + EffectStyleListContext(ContextHandler2Helper const & rParent, EffectStyleList& rEffectStyleList, model::FormatScheme& rFormatScheme); virtual ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) override; private: + model::FormatScheme& mrFormatScheme; + model::EffectStyle* mpEffectStyle; EffectStyleList& mrEffectStyleList; }; } -EffectStyleListContext::EffectStyleListContext( ContextHandler2Helper const & rParent, EffectStyleList& rEffectStyleList ) : - ContextHandler2( rParent ), - mrEffectStyleList( rEffectStyleList ) +EffectStyleListContext::EffectStyleListContext( ContextHandler2Helper const & rParent, EffectStyleList& rEffectStyleList, model::FormatScheme& rFormatScheme) + : ContextHandler2(rParent) + , mrFormatScheme(rFormatScheme) + , mpEffectStyle(nullptr) + , mrEffectStyleList(rEffectStyleList) { } @@ -162,13 +166,17 @@ ContextHandlerRef EffectStyleListContext::onCreateContext( sal_Int32 nElement, c switch( nElement ) { case A_TOKEN( effectStyle ): + { + mpEffectStyle = mrFormatScheme.addEffectStyle(); mrEffectStyleList.push_back( std::make_shared( ) ); return this; - + } case A_TOKEN( effectLst ): // CT_EffectList + { if( mrEffectStyleList.back() ) - return new EffectPropertiesContext( *this, *mrEffectStyleList.back() ); - break; + return new EffectPropertiesContext(*this, *mrEffectStyleList.back(), mpEffectStyle); + } + break; } return nullptr; } @@ -344,7 +352,7 @@ ContextHandlerRef ThemeElementsContext::onCreateContext(sal_Int32 nElement, cons case A_TOKEN( lnStyleLst ): // CT_LineStyleList return new LineStyleListContext(*this, mrOoxTheme.getLineStyleList(), mrTheme.getFormatScheme()); case A_TOKEN( effectStyleLst ): // CT_EffectStyleList - return new EffectStyleListContext( *this, mrOoxTheme.getEffectStyleList() ); + return new EffectStyleListContext(*this, mrOoxTheme.getEffectStyleList(), mrTheme.getFormatScheme()); case A_TOKEN( bgFillStyleLst ): // CT_BackgroundFillStyleList return new BackgroundFillStyleListContext( *this, mrOoxTheme.getBgFillStyleList(), mrTheme.getFormatScheme()); } diff --git a/sw/qa/core/theme/ThemeTest.cxx b/sw/qa/core/theme/ThemeTest.cxx index 27517e64223c..690523d6b006 100644 --- a/sw/qa/core/theme/ThemeTest.cxx +++ b/sw/qa/core/theme/ThemeTest.cxx @@ -21,6 +21,8 @@ using namespace css; +namespace +{ class SwCoreThemeTest : public SwModelTestBase { public: @@ -43,6 +45,43 @@ CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testThemeColorInHeading) CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent1, aThemeColor.getType()); } +void checkEffects(std::vector const& rEffectStyleList) +{ + CPPUNIT_ASSERT_EQUAL(size_t(3), rEffectStyleList.size()); + { + model::EffectStyle rEffectStyle = rEffectStyleList[0]; + CPPUNIT_ASSERT_EQUAL(size_t(0), rEffectStyle.maEffectList.size()); + } + + { + model::EffectStyle rEffectStyle = rEffectStyleList[1]; + CPPUNIT_ASSERT_EQUAL(size_t(0), rEffectStyle.maEffectList.size()); + } + + { + model::EffectStyle rEffectStyle = rEffectStyleList[2]; + CPPUNIT_ASSERT_EQUAL(size_t(1), rEffectStyle.maEffectList.size()); + model::Effect const& rEffect = rEffectStyle.maEffectList[0]; + + CPPUNIT_ASSERT_EQUAL(model::EffectType::OuterShadow, rEffect.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int32(57150), rEffect.mnBlurRadius); + CPPUNIT_ASSERT_EQUAL(sal_Int32(19050), rEffect.mnDistance); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5400000), rEffect.mnDirection); + CPPUNIT_ASSERT_EQUAL(model::RectangleAlignment::Center, rEffect.meAlignment); + CPPUNIT_ASSERT_EQUAL(false, rEffect.mbRotateWithShape); + + CPPUNIT_ASSERT_EQUAL(model::ColorType::RGB, rEffect.maColor.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rEffect.maColor.mnComponent1); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rEffect.maColor.mnComponent2); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rEffect.maColor.mnComponent3); + + CPPUNIT_ASSERT_EQUAL(size_t(1), rEffect.maColor.maTransformations.size()); + CPPUNIT_ASSERT_EQUAL(model::TransformationType::Alpha, + rEffect.maColor.maTransformations[0].meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(6300), rEffect.maColor.maTransformations[0].mnValue); + } +} + CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testDrawPageThemeExistsDOCX) { createSwDoc("ThemeColorInHeading.docx"); @@ -88,6 +127,8 @@ CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testDrawPageThemeExistsDOCX) CPPUNIT_ASSERT_EQUAL(size_t(3), rFormatScheme.getLineStyleList().size()); CPPUNIT_ASSERT_EQUAL(size_t(3), rFormatScheme.getBackgroundFillStyleList().size()); + checkEffects(rFormatScheme.getEffectStyleList()); + // Fill style 1 { model::FillStyle const& rFillStyle = rFormatScheme.getFillStyleList().at(0); @@ -344,6 +385,8 @@ CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testDrawPageThemeExistsODT) CPPUNIT_ASSERT_EQUAL(Color(0xCCDDEA), pTheme->GetColor(model::ThemeColorType::Light2)); } +} // end anonymous namnespace + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit