include/xmloff/xmlstyle.hxx      |    2 
 xmloff/source/draw/ximpstyl.cxx  |    4 -
 xmloff/source/style/xmlstyle.cxx |   90 ++++++++++++++++++++++++++++-----------
 3 files changed, 68 insertions(+), 28 deletions(-)

New commits:
commit b7c6bc0bda7ed0c3dfa46b60face255160df2c19
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Thu Nov 28 16:09:47 2024 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Nov 29 11:04:50 2024 +0100

    tdf#164046 style searching improvement breaks Impress layout
    
    regression from
        commit 6c2f827697b898c9d351b79c2dbb5aefc8b70dcc
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Sun Oct 20 15:07:41 2024 +0200
        improve style searching in SvXMLStylesContext
    
    Two problems - the original code was searching by DisplayName,
    not Name, so add another index for DisplayName,
    and the prefix matching was not properly matching.
    
    Change-Id: Ifd43bdb89d33067954298115c8700b87c7f93050
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177488
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Tested-by: Jenkins

diff --git a/include/xmloff/xmlstyle.hxx b/include/xmloff/xmlstyle.hxx
index a507993e20ae..b370899de3c7 100644
--- a/include/xmloff/xmlstyle.hxx
+++ b/include/xmloff/xmlstyle.hxx
@@ -184,7 +184,7 @@ public:
                                       const OUString& rName,
                                       bool bCreateIndex = false ) const;
     std::pair<StyleIndex::const_iterator, StyleIndex::const_iterator>
-                             FindStyleChildContextByPrefix(
+                             FindStyleChildContextByDisplayNamePrefix(
                                       XmlStyleFamily nFamily,
                                       const OUString& rNamePrefix) const;
     static XmlStyleFamily GetFamily( std::u16string_view rFamily );
diff --git a/xmloff/source/draw/ximpstyl.cxx b/xmloff/source/draw/ximpstyl.cxx
index 067b3012c2dc..28beb4dff118 100644
--- a/xmloff/source/draw/ximpstyl.cxx
+++ b/xmloff/source/draw/ximpstyl.cxx
@@ -1235,7 +1235,7 @@ void SdXMLStylesContext::ImpSetGraphicStyles( 
uno::Reference< container::XNameAc
     sal_Int32 nPrefLen(rPrefix.getLength());
 
     // set defaults
-    auto [itStart1, itEnd1] = FindStyleChildContextByPrefix(nFamily, u""_ustr);
+    auto [itStart1, itEnd1] = 
FindStyleChildContextByDisplayNamePrefix(nFamily, u""_ustr);
     for (auto it = itStart1; it != itEnd1; ++it)
     {
         const SvXMLStyleContext* pStyle = *it;
@@ -1246,7 +1246,7 @@ void SdXMLStylesContext::ImpSetGraphicStyles( 
uno::Reference< container::XNameAc
     }
 
     // create all styles and set properties
-    auto [itStart, itEnd] = FindStyleChildContextByPrefix(nFamily, rPrefix);
+    auto [itStart, itEnd] = FindStyleChildContextByDisplayNamePrefix(nFamily, 
rPrefix);
     for (auto it = itStart; it != itEnd; ++it)
     {
         const SvXMLStyleContext* pStyle = *it;
diff --git a/xmloff/source/style/xmlstyle.cxx b/xmloff/source/style/xmlstyle.cxx
index c0653f026e27..f1b3526ef970 100644
--- a/xmloff/source/style/xmlstyle.cxx
+++ b/xmloff/source/style/xmlstyle.cxx
@@ -153,7 +153,7 @@ bool SvXMLStyleContext::IsTransient() const
 }
 
 namespace {
-struct StyleVectorCompare
+struct StyleIndexCompareByName
 {
     bool operator()(const SvXMLStyleContext* r1, const SvXMLStyleContext* r2) 
const
     {
@@ -164,6 +164,17 @@ struct StyleVectorCompare
         return r1->GetName() < r2->GetName();
     }
 };
+struct StyleIndexCompareByDisplayName
+{
+    bool operator()(const SvXMLStyleContext* r1, const SvXMLStyleContext* r2) 
const
+    {
+        if( r1->GetFamily() < r2->GetFamily() )
+            return true;
+        if( r1->GetFamily() > r2->GetFamily() )
+            return false;
+        return r1->GetDisplayName() < r2->GetDisplayName();
+    }
+};
 }
 
 class SvXMLStylesContext_Impl
@@ -171,7 +182,8 @@ class SvXMLStylesContext_Impl
     std::vector<rtl::Reference<SvXMLStyleContext>> aStyles;
     // it would be better if we could share one vector for the styles and the 
index, but some code in calc
     // is sensitive to having styles re-ordered
-    mutable SvXMLStylesContext::StyleIndex maStylesIndex;
+    mutable SvXMLStylesContext::StyleIndex maStylesIndexByName;
+    mutable SvXMLStylesContext::StyleIndex maStylesIndexByDisplayName;
     bool bAutomaticStyle;
 
 #if OSL_DEBUG_LEVEL > 0
@@ -196,13 +208,14 @@ public:
                                                     bool bCreateIndex ) const;
 
     std::pair<SvXMLStylesContext::StyleIndex::const_iterator, 
SvXMLStylesContext::StyleIndex::const_iterator>
-    FindStyleChildContextByPrefix( XmlStyleFamily nFamily,
+    FindStyleChildContextByDisplayNamePrefix( XmlStyleFamily nFamily,
                                     const OUString& rPrefix ) const;
 
     bool IsAutomaticStyle() const { return bAutomaticStyle; }
 
 private:
-    void BuildIndex() const;
+    void BuildNameIndex() const;
+    void BuildDisplayNameIndex() const;
 };
 
 SvXMLStylesContext_Impl::SvXMLStylesContext_Impl( bool bAuto ) :
@@ -221,7 +234,8 @@ inline void SvXMLStylesContext_Impl::AddStyle( 
SvXMLStyleContext *pStyle )
 #endif
     aStyles.emplace_back(pStyle );
 
-    maStylesIndex.clear();
+    maStylesIndexByName.clear();
+    maStylesIndexByDisplayName.clear();
 }
 
 void SvXMLStylesContext_Impl::dispose()
@@ -235,12 +249,12 @@ const SvXMLStyleContext 
*SvXMLStylesContext_Impl::FindStyleChildContext( XmlStyl
 {
     const SvXMLStyleContext *pStyle = nullptr;
 
-    if( maStylesIndex.empty() && bCreateIndex && !aStyles.empty() )
-        BuildIndex();
+    if( maStylesIndexByName.empty() && bCreateIndex && !aStyles.empty() )
+        BuildNameIndex();
 
-    if( !maStylesIndex.empty() )
+    if( !maStylesIndexByName.empty() )
     {
-        auto it = std::lower_bound(maStylesIndex.begin(), maStylesIndex.end(), 
true,
+        auto it = std::lower_bound(maStylesIndexByName.begin(), 
maStylesIndexByName.end(), true,
             [&nFamily, &rName](const SvXMLStyleContext* lhs, bool /*rhs*/)
             {
                 if (lhs->GetFamily() < nFamily)
@@ -249,7 +263,7 @@ const SvXMLStyleContext 
*SvXMLStylesContext_Impl::FindStyleChildContext( XmlStyl
                     return false;
                 return lhs->GetName() < rName;
             });
-        if (it != maStylesIndex.end() && (*it)->GetFamily() == nFamily && 
(*it)->GetName() == rName)
+        if (it != maStylesIndexByName.end() && (*it)->GetFamily() == nFamily 
&& (*it)->GetName() == rName)
             pStyle = *it;
     }
     else
@@ -267,7 +281,7 @@ const SvXMLStyleContext 
*SvXMLStylesContext_Impl::FindStyleChildContext( XmlStyl
 
 namespace
 {
-struct PrefixProbe
+struct PrefixProbeLowerBound
 {
     XmlStyleFamily nFamily;
     const OUString& rPrefix;
@@ -278,36 +292,54 @@ struct PrefixProbe
             return true;
         if (lhs->GetFamily() > nFamily)
             return false;
-        const OUString& lhsName = lhs->GetName();
-        return lhsName.subView(0, std::min(lhsName.getLength(), 
rPrefix.getLength())) < rPrefix;
+        return lhs->GetDisplayName() < rPrefix;
     }
+};
+struct PrefixProbeUpperBound
+{
+    XmlStyleFamily nFamily;
+    const OUString& rPrefix;
+
     bool operator()(bool /*lhs*/, const SvXMLStyleContext* rhs)
     {
         if (nFamily < rhs->GetFamily())
             return true;
         if (nFamily > rhs->GetFamily())
             return false;
-        const OUString& rhsName = rhs->GetName();
-        return rPrefix < rhsName.subView(0, std::min(rhsName.getLength(), 
rPrefix.getLength()));
+        std::u16string_view rhsName = rhs->GetDisplayName();
+        // For the upper bound we want to view the vector's data as if
+        // every element was truncated to the size of the prefix.
+        // Then perform a normal match.
+        rhsName = rhsName.substr(0, rPrefix.getLength());
+        // compare UP TO the length of the prefix and no farther
+        if (int cmp = rPrefix.compareTo(rhsName))
+            return cmp < 0;
+        // The strings are equal to the length of the prefix so
+        // behave as if they are equal. That means s1 < s2 == false
+        return false;
     }
 };
 }
 
 std::pair<SvXMLStylesContext::StyleIndex::const_iterator, 
SvXMLStylesContext::StyleIndex::const_iterator>
-SvXMLStylesContext_Impl::FindStyleChildContextByPrefix( XmlStyleFamily nFamily,
+SvXMLStylesContext_Impl::FindStyleChildContextByDisplayNamePrefix( 
XmlStyleFamily nFamily,
                                                         const OUString& 
rPrefix ) const
 {
-    if( maStylesIndex.empty() )
-        BuildIndex();
-    return std::equal_range(maStylesIndex.begin(), maStylesIndex.end(), true, 
PrefixProbe{nFamily,rPrefix});
+    if( maStylesIndexByDisplayName.empty() )
+        BuildDisplayNameIndex();
+    auto itStart = std::lower_bound(maStylesIndexByDisplayName.begin(), 
maStylesIndexByDisplayName.end(), true, PrefixProbeLowerBound{nFamily,rPrefix});
+    auto itEnd = std::upper_bound(itStart, maStylesIndexByDisplayName.end(), 
true, PrefixProbeUpperBound{nFamily,rPrefix});
+    return {itStart, itEnd};
 }
 
-void SvXMLStylesContext_Impl::BuildIndex() const
+void SvXMLStylesContext_Impl::BuildNameIndex() const
 {
-    maStylesIndex.reserve(aStyles.size());
+    maStylesIndexByName.reserve(aStyles.size());
+
     for (const auto & i : aStyles)
-        maStylesIndex.push_back(i.get());
-    std::sort(maStylesIndex.begin(), maStylesIndex.end(), 
StyleVectorCompare());
+        maStylesIndexByName.push_back(i.get());
+    std::sort(maStylesIndexByName.begin(), maStylesIndexByName.end(), 
StyleIndexCompareByName());
+
 #if OSL_DEBUG_LEVEL > 0
     SAL_WARN_IF(0 != m_nIndexCreated, "xmloff.style",
                 "Performance warning: sdbcx::Index created multiple times");
@@ -315,6 +347,14 @@ void SvXMLStylesContext_Impl::BuildIndex() const
 #endif
 }
 
+void SvXMLStylesContext_Impl::BuildDisplayNameIndex() const
+{
+    maStylesIndexByDisplayName.reserve(aStyles.size());
+    for (const auto & i : aStyles)
+        maStylesIndexByDisplayName.push_back(i.get());
+    std::sort(maStylesIndexByDisplayName.begin(), 
maStylesIndexByDisplayName.end(), StyleIndexCompareByDisplayName());
+}
+
 sal_uInt32 SvXMLStylesContext::GetStyleCount() const
 {
     return mpImpl->GetStyleCount();
@@ -830,11 +870,11 @@ const SvXMLStyleContext 
*SvXMLStylesContext::FindStyleChildContext(
 }
 
 std::pair<SvXMLStylesContext::StyleIndex::const_iterator, 
SvXMLStylesContext::StyleIndex::const_iterator>
-SvXMLStylesContext::FindStyleChildContextByPrefix(
+SvXMLStylesContext::FindStyleChildContextByDisplayNamePrefix(
                                   XmlStyleFamily nFamily,
                                   const OUString& rNamePrefix ) const
 {
-    return mpImpl->FindStyleChildContextByPrefix( nFamily, rNamePrefix );
+    return mpImpl->FindStyleChildContextByDisplayNamePrefix( nFamily, 
rNamePrefix );
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to