svx/source/accessibility/ChildrenManagerImpl.cxx |  135 ++++++++++++-----------
 1 file changed, 75 insertions(+), 60 deletions(-)

New commits:
commit 7ea5763aa766d0b4f25b0f089873dc2c8726cec5
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Tue Aug 17 15:43:00 2021 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Aug 18 10:15:56 2021 +0200

    Resolves: tdf#139220 with ~1000 selected shapes a11y UpdateSelection crawls
    
    so fetch the selected shapes once and sort them for quick lookup in the
    loop over maVisibleChildren.
    
    As an side, not changed here, SvxShapeCollection::getByIndex looks
    suboptimal with a body of
    
    std::vector<Reference<uno::XInterface>> 
aElements(maShapeContainer.getElements());
    return uno::makeAny(Reference<drawing::XShape>(aElements[Index].get()));
    
    Change-Id: Idec7c003e7c5ee02000d4642d4fdb0d940548d97
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120583
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/svx/source/accessibility/ChildrenManagerImpl.cxx 
b/svx/source/accessibility/ChildrenManagerImpl.cxx
index 53d1e7596b6b..573427c4714e 100644
--- a/svx/source/accessibility/ChildrenManagerImpl.cxx
+++ b/svx/source/accessibility/ChildrenManagerImpl.cxx
@@ -38,6 +38,7 @@
 #include <com/sun/star/container/XChild.hpp>
 #include <comphelper/types.hxx>
 #include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
 #include <rtl/ustring.hxx>
 #include <tools/debug.hxx>
 #include <svx/SvxShapeTypes.hxx>
@@ -793,20 +794,6 @@ uno::Reference<XAccessible>
 */
 void ChildrenManagerImpl::UpdateSelection()
 {
-    Reference<frame::XController> xController(maShapeTreeInfo.GetController());
-    Reference<view::XSelectionSupplier> xSelectionSupplier (
-        xController, uno::UNO_QUERY);
-
-    // Try to cast the selection both to a multi selection and to a single
-    // selection.
-    Reference<container::XIndexAccess> xSelectedShapeAccess;
-    Reference<drawing::XShape> xSelectedShape;
-    if (xSelectionSupplier.is())
-    {
-        xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), 
uno::UNO_QUERY);
-        xSelectedShape.set( xSelectionSupplier->getSelection(), 
uno::UNO_QUERY);
-    }
-
     // Remember the current and new focused shape.
     AccessibleShape* pCurrentlyFocusedShape = nullptr;
     AccessibleShape* pNewFocusedShape = nullptr;
@@ -815,73 +802,101 @@ void ChildrenManagerImpl::UpdateSelection()
     VEC_SHAPE vecSelect;
     int nAddSelect=0;
     bool bHasSelectedShape=false;
-    for (const auto& rChild : maVisibleChildren)
+    if (!maVisibleChildren.empty())
     {
-        AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
-        if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && 
pAccessibleShape!=nullptr)
+        Reference<frame::XController> 
xController(maShapeTreeInfo.GetController());
+        Reference<view::XSelectionSupplier> xSelectionSupplier (
+            xController, uno::UNO_QUERY);
+
+        // Try to cast the selection both to a multi selection and to a single
+        // selection.
+        Reference<container::XIndexAccess> xSelectedShapeAccess;
+        Reference<drawing::XShape> xSelectedShape;
+        if (xSelectionSupplier.is())
         {
-            short nRole = pAccessibleShape->getAccessibleRole();
-            bool bDrawShape = (
-                nRole == AccessibleRole::GRAPHIC ||
-                nRole == AccessibleRole::EMBEDDED_OBJECT ||
-                nRole == AccessibleRole::SHAPE ||
-                nRole == AccessibleRole::IMAGE_MAP ||
-                nRole == AccessibleRole::TABLE_CELL ||
-                nRole == AccessibleRole::TABLE );
-            bool bShapeIsSelected = false;
-
-            // Look up the shape in the (single or multi-) selection.
-            if (xSelectedShape.is())
+            xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), 
uno::UNO_QUERY);
+            xSelectedShape.set( xSelectionSupplier->getSelection(), 
uno::UNO_QUERY);
+        }
+
+        // tdf#139220 to quickly find if a given drawing::XShape is selected
+        o3tl::sorted_vector<css::uno::Reference<css::drawing::XShape>> 
aSortedSelectedShapes;
+        if (!xSelectedShape.is() && xSelectedShapeAccess.is())
+        {
+            sal_Int32 nCount = xSelectedShapeAccess->getCount();
+            aSortedSelectedShapes.reserve(nCount);
+            for (sal_Int32 i = 0; i < nCount; ++i)
             {
-                if  (rChild.mxShape == xSelectedShape)
-                {
-                    bShapeIsSelected = true;
-                    pNewFocusedShape = pAccessibleShape;
-                }
+                css::uno::Reference<css::drawing::XShape> 
xShape(xSelectedShapeAccess->getByIndex(i), uno::UNO_QUERY);
+                aSortedSelectedShapes.insert(xShape);
             }
-            else if (xSelectedShapeAccess.is())
+        }
+
+        for (const auto& rChild : maVisibleChildren)
+        {
+            AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
+            if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && 
pAccessibleShape!=nullptr)
             {
-                sal_Int32 nCount=xSelectedShapeAccess->getCount();
-                for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
-                    if (xSelectedShapeAccess->getByIndex(i) == rChild.mxShape)
+                short nRole = pAccessibleShape->getAccessibleRole();
+                bool bDrawShape = (
+                    nRole == AccessibleRole::GRAPHIC ||
+                    nRole == AccessibleRole::EMBEDDED_OBJECT ||
+                    nRole == AccessibleRole::SHAPE ||
+                    nRole == AccessibleRole::IMAGE_MAP ||
+                    nRole == AccessibleRole::TABLE_CELL ||
+                    nRole == AccessibleRole::TABLE );
+                bool bShapeIsSelected = false;
+
+                // Look up the shape in the (single or multi-) selection.
+                if (xSelectedShape.is())
+                {
+                    if  (rChild.mxShape == xSelectedShape)
+                    {
+                        bShapeIsSelected = true;
+                        pNewFocusedShape = pAccessibleShape;
+                    }
+                }
+                else if (!aSortedSelectedShapes.empty())
+                {
+                    if (aSortedSelectedShapes.find(rChild.mxShape) != 
aSortedSelectedShapes.end())
                     {
                         bShapeIsSelected = true;
                         // In a multi-selection no shape has the focus.
-                        if (nCount == 1)
+                        if (aSortedSelectedShapes.size() == 1)
                             pNewFocusedShape = pAccessibleShape;
                     }
-            }
+                }
 
-            // Set or reset the SELECTED state.
-            if (bShapeIsSelected)
-            {
-                if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
+                // Set or reset the SELECTED state.
+                if (bShapeIsSelected)
                 {
-                    if (bDrawShape)
+                    if (pAccessibleShape->SetState 
(AccessibleStateType::SELECTED))
                     {
-                        vecSelect.emplace_back(pAccessibleShape,true);
-                        ++nAddSelect;
+                        if (bDrawShape)
+                        {
+                            vecSelect.emplace_back(pAccessibleShape,true);
+                            ++nAddSelect;
+                        }
+                    }
+                    else
+                    {//Selected not change,has selected shape before
+                        bHasSelectedShape=true;
                     }
                 }
                 else
-                {//Selected not change,has selected shape before
-                    bHasSelectedShape=true;
-                }
-            }
-            else
-                //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
-            {
-                if(pAccessibleShape->ResetState 
(AccessibleStateType::SELECTED))
+                    //pAccessibleShape->ResetState 
(AccessibleStateType::SELECTED);
                 {
-                    if(bDrawShape)
+                    if(pAccessibleShape->ResetState 
(AccessibleStateType::SELECTED))
                     {
-                        vecSelect.emplace_back(pAccessibleShape,false);
+                        if(bDrawShape)
+                        {
+                            vecSelect.emplace_back(pAccessibleShape,false);
+                        }
                     }
                 }
+                // Does the shape have the current selection?
+                if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
+                    pCurrentlyFocusedShape = pAccessibleShape;
             }
-            // Does the shape have the current selection?
-            if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
-                pCurrentlyFocusedShape = pAccessibleShape;
         }
     }
 

Reply via email to