oox/inc/drawingml/customshapeproperties.hxx | 33 ++++++-- oox/source/drawingml/customshapegeometry.cxx | 30 +++---- oox/source/drawingml/customshapeproperties.cxx | 99 ++++++++++++++++--------- oox/source/drawingml/shape.cxx | 2 oox/source/drawingml/transform2dcontext.cxx | 12 +-- 5 files changed, 113 insertions(+), 63 deletions(-)
New commits: commit 2a5fc2a414517bfcef164f527ef7ab1658fcef5d Author: Aron Budea <aron.bu...@collabora.com> AuthorDate: Tue Apr 30 03:39:15 2024 +0200 Commit: Aron Budea <aron.bu...@collabora.com> CommitDate: Thu May 2 06:32:02 2024 +0200 tdf#148616 Speed up finding custom shape guide value Use a lookup hash map instead of linear search Change-Id: I54c9509740d90ca3f7479dfc16a6aeffd82a405d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166879 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Reviewed-by: Aron Budea <aron.bu...@collabora.com> diff --git a/oox/inc/drawingml/customshapeproperties.hxx b/oox/inc/drawingml/customshapeproperties.hxx index 4b9ee40503cd..1c627ec7448f 100644 --- a/oox/inc/drawingml/customshapeproperties.hxx +++ b/oox/inc/drawingml/customshapeproperties.hxx @@ -42,6 +42,28 @@ struct CustomShapeGuide OUString maFormula; }; +class CustomShapeGuideContainer +{ +public: + sal_Int32 GetCustomShapeGuideValue( const OUString& rFormulaName ) const; + sal_Int32 SetCustomShapeGuideValue( const CustomShapeGuide& rGuide ); + + void push_back( const CustomShapeGuide& rGuide ); + size_t size() const { return maGuideList.size(); }; + bool empty() const { return maGuideList.empty(); }; + std::vector< CustomShapeGuide >::const_iterator begin() const { return maGuideList.begin(); }; + std::vector< CustomShapeGuide >::const_iterator end() const { return maGuideList.end(); }; + const CustomShapeGuide& operator[](size_t nIndex) const { return maGuideList[ nIndex ]; }; + +private: + std::vector< CustomShapeGuide > maGuideList; + mutable std::unordered_map< OUString, sal_Int32 > maGuideListLookupMap; + mutable bool mbLookupMapStale = false; + mutable sal_Int32 mnPreviousActSize = 0; + + void ActualizeLookupMap() const; +}; + struct AdjustHandle { bool polar; @@ -106,8 +128,8 @@ public: bool getShapeTypeOverride() const { return mbShapeTypeOverride; }; void setShapeTypeOverride( bool bShapeTypeOverride ) { mbShapeTypeOverride = bShapeTypeOverride; }; - std::vector< CustomShapeGuide >& getAdjustmentGuideList(){ return maAdjustmentGuideList; }; - std::vector< CustomShapeGuide >& getGuideList(){ return maGuideList; }; + CustomShapeGuideContainer& getAdjustmentGuideList(){ return maAdjustmentGuideList; }; + CustomShapeGuideContainer& getGuideList(){ return maGuideList; }; std::vector< AdjustHandle >& getAdjustHandleList(){ return maAdjustHandleList; }; std::vector< ConnectionSite >& getConnectionSiteList(){ return maConnectionSiteList; }; std::optional< GeomRect >& getTextRect(){ return maTextRect; }; @@ -119,9 +141,6 @@ public: void setTextCameraZRotateAngle( sal_Int32 nAngle ) { mnTextCameraZRotateAngle = nAngle; }; void setTextAreaRotateAngle(sal_Int32 nAngle) { moTextAreaRotateAngle = nAngle; }; - static sal_Int32 SetCustomShapeGuideValue( std::vector< CustomShapeGuide >& rGuideList, const CustomShapeGuide& rGuide ); - static sal_Int32 GetCustomShapeGuideValue( const std::vector< CustomShapeGuide >& rGuideList, std::u16string_view rFormulaName ); - sal_Int32 getArcNum() { return mnArcNum++; } sal_Int32 countArcTo() { return mnArcNum; } PropertyMap& getExtrusionPropertyMap() { return maExtrusionPropertyMap; } @@ -136,8 +155,8 @@ private: sal_Int32 mnShapePresetType; bool mbShapeTypeOverride; - std::vector< CustomShapeGuide > maAdjustmentGuideList; - std::vector< CustomShapeGuide > maGuideList; + CustomShapeGuideContainer maAdjustmentGuideList; + CustomShapeGuideContainer maGuideList; std::vector< AdjustHandle > maAdjustHandleList; std::vector< ConnectionSite > maConnectionSiteList; std::optional< GeomRect > maTextRect; diff --git a/oox/source/drawingml/customshapegeometry.cxx b/oox/source/drawingml/customshapegeometry.cxx index 01b86b4eea1b..b029957959d8 100644 --- a/oox/source/drawingml/customshapegeometry.cxx +++ b/oox/source/drawingml/customshapegeometry.cxx @@ -224,7 +224,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "logheight" ; - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } else @@ -259,7 +259,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "logheight/" + OUString::number( nIntVal ); - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } break; @@ -278,7 +278,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "max(logwidth,logheight)"; - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } break; @@ -288,7 +288,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "min(logwidth,logheight)"; - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } break; @@ -315,7 +315,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "min(logwidth,logheight)/" + OUString::number( nIntVal ); - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } break; @@ -329,7 +329,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "logwidth" ; - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } else @@ -370,7 +370,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu aGuide.maName = rValue; aGuide.maFormula = "logwidth/" + OUString::number( nIntVal ); - aRet.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), aGuide ); + aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );; aRet.Type = EnhancedCustomShapeParameterType::EQUATION; } break; @@ -401,7 +401,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu } else { - sal_Int32 nGuideIndex = CustomShapeProperties::GetCustomShapeGuideValue( rCustomShapeProperties.getAdjustmentGuideList(), rValue ); + sal_Int32 nGuideIndex = rCustomShapeProperties.getAdjustmentGuideList().GetCustomShapeGuideValue( rValue ); if ( nGuideIndex >= 0 ) { aRet.Value <<= nGuideIndex; @@ -409,7 +409,7 @@ static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCu } else { - nGuideIndex = CustomShapeProperties::GetCustomShapeGuideValue( rCustomShapeProperties.getGuideList(), rValue ); + nGuideIndex = rCustomShapeProperties.getGuideList().GetCustomShapeGuideValue( rValue ); if ( nGuideIndex >= 0 ) { aRet.Value <<= nGuideIndex; @@ -433,17 +433,17 @@ namespace { class GeomGuideListContext : public ContextHandler2 { public: - GeomGuideListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, std::vector< CustomShapeGuide >& rGuideList ); + GeomGuideListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, CustomShapeGuideContainer& rGuideList ); virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override; protected: - std::vector< CustomShapeGuide >& mrGuideList; - CustomShapeProperties& mrCustomShapeProperties; + CustomShapeGuideContainer& mrGuideList; + CustomShapeProperties& mrCustomShapeProperties; }; } -GeomGuideListContext::GeomGuideListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, std::vector< CustomShapeGuide >& rGuideList ) +GeomGuideListContext::GeomGuideListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, CustomShapeGuideContainer& rGuideList ) : ContextHandler2( rParent ) , mrGuideList( rGuideList ) , mrCustomShapeProperties( rCustomShapeProperties ) @@ -1110,7 +1110,7 @@ ContextHandlerRef Path2DContext::onCreateContext( sal_Int32 aElementToken, aGuide.maFormula = "(" + GetFormulaParameter( GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_stAng ) ) ) + ")/60000.0"; - aAngles.First.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( mrCustomShapeProperties.getGuideList(), aGuide ); + aAngles.First.Value <<= mrCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aAngles.First.Type = EnhancedCustomShapeParameterType::EQUATION; // swing angle @@ -1118,7 +1118,7 @@ ContextHandlerRef Path2DContext::onCreateContext( sal_Int32 aElementToken, aGuide.maFormula = "(" + GetFormulaParameter( GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_swAng ) ) ) + ")/60000.0"; - aAngles.Second.Value <<= CustomShapeProperties::SetCustomShapeGuideValue( mrCustomShapeProperties.getGuideList(), aGuide ); + aAngles.Second.Value <<= mrCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide ); aAngles.Second.Type = EnhancedCustomShapeParameterType::EQUATION; mrPath2D.parameter.push_back( aScale ); diff --git a/oox/source/drawingml/customshapeproperties.cxx b/oox/source/drawingml/customshapeproperties.cxx index a3e2dd5e10bb..f5dfae2e56df 100644 --- a/oox/source/drawingml/customshapeproperties.cxx +++ b/oox/source/drawingml/customshapeproperties.cxx @@ -43,6 +43,67 @@ using namespace ::com::sun::star::drawing; namespace oox::drawingml { +void CustomShapeGuideContainer::ActualizeLookupMap() const +{ + if ( mbLookupMapStale ) + { + // maGuideListLookupMap maps guide name to index in maGuideList + // guides were added since last actualization, need to update map based on those + // guide names can be reused, and current is the latest one + // (see a1 guide in gear6 custom shape preset as example): + // go backwards and update if index is higher than previously + for ( sal_Int32 nIndex = static_cast<sal_Int32>( maGuideList.size() ) - 1; nIndex >= mnPreviousActSize; --nIndex ) + { + const auto it = maGuideListLookupMap.find( maGuideList[ nIndex ].maName ); + if ( it != maGuideListLookupMap.end() ) + { + if ( nIndex > it->second ) + it->second = nIndex; + } + else + maGuideListLookupMap[ maGuideList[ nIndex ].maName ] = nIndex; + } + mbLookupMapStale = false; + mnPreviousActSize = static_cast<sal_Int32>( maGuideList.size() ); + } +} + +void CustomShapeGuideContainer::push_back( const CustomShapeGuide& rGuide ) +{ + if ( !mbLookupMapStale ) + { + mbLookupMapStale = true; + mnPreviousActSize = static_cast<sal_Int32>( maGuideList.size() ); + } + maGuideList.push_back( rGuide ); +} + +// returns the index into the guidelist for a given formula name, +// if the return value is < 0 then the guide value could not be found +sal_Int32 CustomShapeGuideContainer::GetCustomShapeGuideValue( const OUString &rFormulaName ) const +{ + ActualizeLookupMap(); + const auto it = maGuideListLookupMap.find( rFormulaName ); + if ( it != maGuideListLookupMap.end() ) + return it->second; + + return -1; +} + +sal_Int32 CustomShapeGuideContainer::SetCustomShapeGuideValue( const CustomShapeGuide& rGuide ) +{ + ActualizeLookupMap(); + // change from previous SetCustomShapeGuideValue behavior: searching using cache traverses backwards + const auto it = maGuideListLookupMap.find( rGuide.maName ); + if ( it != maGuideListLookupMap.end() ) + return it->second; + + maGuideList.push_back( rGuide ); + maGuideListLookupMap[ rGuide.maName ] = mnPreviousActSize; + mnPreviousActSize++; + return mnPreviousActSize - 1; +} + CustomShapeProperties::CustomShapeProperties() : mnShapePresetType ( -1 ) , mbShapeTypeOverride(false) @@ -59,36 +120,6 @@ OUString CustomShapeProperties::getShapePresetTypeName() const return StaticTokenMap().getUnicodeTokenName(mnShapePresetType); } -sal_Int32 CustomShapeProperties::SetCustomShapeGuideValue( std::vector< CustomShapeGuide >& rGuideList, const CustomShapeGuide& rGuide ) -{ - std::vector<CustomShapeGuide>::size_type nIndex = 0; - for( ; nIndex < rGuideList.size(); nIndex++ ) - { - if ( rGuideList[ nIndex ].maName == rGuide.maName ) - break; - } - if ( nIndex == rGuideList.size() ) - rGuideList.push_back( rGuide ); - return static_cast< sal_Int32 >( nIndex ); -} - -// returns the index into the guidelist for a given formula name, -// if the return value is < 0 then the guide value could not be found -sal_Int32 CustomShapeProperties::GetCustomShapeGuideValue( const std::vector< CustomShapeGuide >& rGuideList, std::u16string_view rFormulaName ) -{ - // traverse the list from the end, because guide names can be reused - // and current is the last one - // see a1 guide in gear6 custom shape preset as example - sal_Int32 nIndex = static_cast< sal_Int32 >( rGuideList.size() ) - 1; - for( ; nIndex >= 0; nIndex-- ) - { - if ( rGuideList[ nIndex ].maName == rFormulaName ) - break; - } - - return nIndex; -} - bool CustomShapeProperties::representsDefaultShape() const { return !((getShapePresetType() >= 0 || maPath2DList.size() > 0) && @@ -315,13 +346,13 @@ void CustomShapeProperties::pushToPropSet( aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos); if ( maAdjustHandleList[ i ].gdRef1.has_value() ) { - sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef1.value() ); + sal_Int32 nIndex = maAdjustmentGuideList.GetCustomShapeGuideValue( maAdjustHandleList[ i ].gdRef1.value() ); if ( nIndex >= 0 ) aHandle.setProperty( PROP_RefR, nIndex); } if ( maAdjustHandleList[ i ].gdRef2.has_value() ) { - sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef2.value() ); + sal_Int32 nIndex = maAdjustmentGuideList.GetCustomShapeGuideValue( maAdjustHandleList[ i ].gdRef2.value() ); if ( nIndex >= 0 ) aHandle.setProperty( PROP_RefAngle, nIndex); } @@ -344,13 +375,13 @@ void CustomShapeProperties::pushToPropSet( { // TODO: PROP_RefX and PROP_RefY are not yet part of our file format, // so the handles will not work after save/reload - sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef1.value() ); + sal_Int32 nIndex = maAdjustmentGuideList.GetCustomShapeGuideValue( maAdjustHandleList[ i ].gdRef1.value() ); if ( nIndex >= 0 ) aHandle.setProperty( PROP_RefX, nIndex); } if ( maAdjustHandleList[ i ].gdRef2.has_value() ) { - sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef2.value() ); + sal_Int32 nIndex = maAdjustmentGuideList.GetCustomShapeGuideValue( maAdjustHandleList[ i ].gdRef2.value() ); if ( nIndex >= 0 ) aHandle.setProperty( PROP_RefY, nIndex); } diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 23be28b546b6..5b2109ca2d88 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -1878,7 +1878,7 @@ Reference< XShape > const & Shape::createAndInsert( { msConnectorName = mpCustomShapePropertiesPtr->getShapePresetTypeName(); - auto aAdjustmentList = mpCustomShapePropertiesPtr->getAdjustmentGuideList(); + const auto& aAdjustmentList = mpCustomShapePropertiesPtr->getAdjustmentGuideList(); for (size_t i = 0; i < aAdjustmentList.size(); i++) maConnectorAdjustmentList.push_back(aAdjustmentList[i].maFormula); diff --git a/oox/source/drawingml/transform2dcontext.cxx b/oox/source/drawingml/transform2dcontext.cxx index 1cd67d1192db..656cb41a4b7f 100644 --- a/oox/source/drawingml/transform2dcontext.cxx +++ b/oox/source/drawingml/transform2dcontext.cxx @@ -80,7 +80,7 @@ bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) case XML_round2SameRect: { // Second handle of round2SameRect used in preset diagrams has value 0. - auto aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); + const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); double fAdj = aAdjGdList.empty() ? 16667 : aAdjGdList[0].maFormula.toDouble(); sal_Int32 nWidth = rShape.getSize().Width; sal_Int32 nHeight = rShape.getSize().Height; @@ -98,7 +98,7 @@ bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) } case XML_trapezoid: { - auto aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); + const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); double fAdj = aAdjGdList.empty() ? 25000 : aAdjGdList[0].maFormula.toDouble(); sal_Int32 nWidth = rShape.getSize().Width; sal_Int32 nHeight = rShape.getSize().Height; @@ -144,7 +144,7 @@ bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) return false; double a1(15000.0); double a2(3526.0); - auto aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); + const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); if (aAdjGdList.size() == 2) { a1 = aAdjGdList[0].maFormula.toDouble(); @@ -186,7 +186,7 @@ bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) } case XML_hexagon: { - auto aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); + const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); double fAdj = aAdjGdList.empty() ? 25000 : aAdjGdList[0].maFormula.toDouble(); sal_Int32 nWidth = rShape.getSize().Width; sal_Int32 nHeight = rShape.getSize().Height; @@ -209,7 +209,7 @@ bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) sal_Int32 nHeight = rShape.getSize().Height; if (nWidth == 0 || nHeight == 0) return false; - auto aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); + const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); double fAdj = aAdjGdList.empty() ? 16667.0 : aAdjGdList[0].maFormula.toDouble(); fAdj = std::clamp<double>(fAdj, 0.0, 50000.0); double fDx = std::min(nWidth, nHeight) * fAdj / 100000.0 * 0.29289; @@ -228,7 +228,7 @@ bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) return false; double a1(50000.0); double a2(50000.0); - auto aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); + const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); if (aAdjGdList.size() == 2) { a1 = aAdjGdList[0].maFormula.toDouble();