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.grandin@collabora.co.uk>
Reviewed-by: Aron Budea <aron.budea@collabora.com>
diff --git a/oox/inc/drawingml/customshapeproperties.hxx b/oox/inc/drawingml/customshapeproperties.hxx
index 4b9ee40..1c627ec 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 01b86b4..b029957 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 a3e2dd5..f5dfae2 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 23be28b..5b2109c 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 1cd67d1..656cb41 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();