tdf#146626 catch IndexOutOfBoundsException when fetching accessible children

com::sun::star::accessibility::XAccessibleContext::getAccessibleChild()
can throw an IndexOutOfBoundsException exception even when fetching with
an index that is positive and less than the value returned by a call to
the accessible context's getAccessibleChildCount() method so put every
getAccessibleChild() call in a try/catch block.

Note: this is actually expected behavior even though it is rare. For
example, accessibility::AccessibleTextHelper_Impl::getAccessibleChild()
uses the following code snippet to throw such an exception:

    if( 0 > i || i >= getAccessibleChildCount() ||
        GetTextForwarder().GetParagraphCount() <= i )

In the case of tdf#146626, getAccessibleChildCount() returns 22 but
getAccessibleChild(1) throws such an exception due to the last
condition in the above code snippet.

Change-Id: If974afb7b9178faa99b91dcd79eb5f169bbfe13e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153160
Tested-by: Jenkins
Reviewed-by: Patrick Luby <plubius@neooffice.org>
diff --git a/vcl/osx/a11yfocustracker.cxx b/vcl/osx/a11yfocustracker.cxx
index 8d830cd..2aaa8b0 100644
--- a/vcl/osx/a11yfocustracker.cxx
+++ b/vcl/osx/a11yfocustracker.cxx
@@ -30,8 +30,10 @@
#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>

using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;

AquaA11yFocusTracker& TheAquaA11yFocusTracker()
@@ -118,10 +120,16 @@ void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)

        if( xContext.is() )
        {
            ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
            if( nPos != ToolBox::ITEM_NOTFOUND )
                setFocusedObject( xContext->getAccessibleChild( nPos ) );
                    //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
            try {
                ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
                if( nPos != ToolBox::ITEM_NOTFOUND )
                    setFocusedObject( xContext->getAccessibleChild( nPos ) );
                        //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
            }
            catch (const IndexOutOfBoundsException&)
            {
                SAL_WARN("vcl", "Accessible object has invalid index in parent");
            }
        }
    }
}
@@ -150,11 +158,17 @@ void AquaA11yFocusTracker::toolbox_open_floater(vcl::Window *pWindow)
            return;
        }
        if ( rxContext -> getAccessibleChildCount() > 0 ) {
            Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
            if ( ! rxAccessibleChild.is() ) {
                return;
            try {
                Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
                if ( ! rxAccessibleChild.is() ) {
                    return;
                }
                setFocusedObject ( rxAccessibleChild );
            }
            setFocusedObject ( rxAccessibleChild );
            catch (const IndexOutOfBoundsException&)
            {
                SAL_WARN("vcl", "No valid accessible objects in parent");
            }
        }
    }
}
diff --git a/vcl/osx/a11yrolehelper.mm b/vcl/osx/a11yrolehelper.mm
index 5cb75c9..e95036d 100644
--- a/vcl/osx/a11yrolehelper.mm
+++ b/vcl/osx/a11yrolehelper.mm
@@ -24,8 +24,12 @@

#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>

#include <sal/log.hxx>

using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;

@implementation AquaA11yRoleHelper
@@ -153,17 +157,23 @@ using namespace ::com::sun::star::uno;
            }
        }
    } else if ( accessibleContext -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
        Reference < XAccessible > rxAccessible = accessibleContext -> getAccessibleChild(0);
        if ( rxAccessible.is() ) {
            Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
            if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) {
                sal_Int64 nStateSet = rxAccessibleContext -> getAccessibleStateSet();
                if ( !(nStateSet & AccessibleStateType::EDITABLE ) ) {
                    [ nativeRole release ];
                    nativeRole = NSAccessibilityPopUpButtonRole;
        try {
            Reference < XAccessible > rxAccessible = accessibleContext -> getAccessibleChild(0);
            if ( rxAccessible.is() ) {
                Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
                if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) {
                    sal_Int64 nStateSet = rxAccessibleContext -> getAccessibleStateSet();
                    if ( !(nStateSet & AccessibleStateType::EDITABLE ) ) {
                        [ nativeRole release ];
                        nativeRole = NSAccessibilityPopUpButtonRole;
                    }
                }
            }
        }
        catch (const IndexOutOfBoundsException&)
        {
            SAL_WARN("vcl", "No valid accessible objects in parent");
        }
    }
    return nativeRole;
}
diff --git a/vcl/osx/a11ywrapper.mm b/vcl/osx/a11ywrapper.mm
index 06967df..0ca256a 100644
--- a/vcl/osx/a11ywrapper.mm
+++ b/vcl/osx/a11ywrapper.mm
@@ -45,6 +45,7 @@
#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>

#include <sal/log.hxx>
#include <osl/diagnose.h>
@@ -339,19 +340,25 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) {
            NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
            Reference< XAccessibleContext > xContext( [ self accessibleContext ] );

            sal_Int64 cnt = xContext -> getAccessibleChildCount();
            for ( sal_Int64 i = 0; i < cnt; i++ ) {
                Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
                if( xChild.is() ) {
                    Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
                    // the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
                    if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
                        id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
                        [ children addObject: wrapper ];
                        [ wrapper release ];
            try {
                sal_Int64 cnt = xContext -> getAccessibleChildCount();
                for ( sal_Int64 i = 0; i < cnt; i++ ) {
                    Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
                    if( xChild.is() ) {
                        Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
                        // the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
                        if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
                            id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
                            [ children addObject: wrapper ];
                            [ wrapper release ];
                        }
                    }
                }
            }
            catch (const IndexOutOfBoundsException&)
            {
                SAL_WARN("vcl", "Accessible object has invalid index in parent");
            }

            // if not already acting as RadioGroup now is the time to replace RadioButtons with RadioGroups and remove RadioButtons
            if ( ! mActsAsRadioGroup ) {
@@ -1063,16 +1070,22 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point,
            }

            if( bSafeToIterate ) {
                for ( sal_Int64 i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
                    Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
                    if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
                        Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
                        if ( myHitChild.is() ) {
                            hitChild = myHitChild;
                            break;
                try {
                    for ( sal_Int64 i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
                        Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
                        if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
                            Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
                            if ( myHitChild.is() ) {
                                hitChild = myHitChild;
                                break;
                            }
                        }
                    }
                }
                catch (const IndexOutOfBoundsException&)
                {
                    SAL_WARN("vcl", "Accessible object has invalid index in parent");
                }
            }
        }
    } catch ( RuntimeException ) {
diff --git a/vcl/osx/documentfocuslistener.cxx b/vcl/osx/documentfocuslistener.cxx
index 5f39e7c..44a3506 100644
--- a/vcl/osx/documentfocuslistener.cxx
+++ b/vcl/osx/documentfocuslistener.cxx
@@ -106,7 +106,13 @@ Reference< XAccessible > DocumentFocusListener::getAccessible(const EventObject&
            Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
            if( xParentContext.is() )
            {
                return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
                try {
                    return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
                }
                catch (const IndexOutOfBoundsException&)
                {
                    SAL_WARN("vcl", "Accessible object has invalid index in parent");
                }
            }
        }
    }
@@ -153,13 +159,19 @@ void DocumentFocusListener::attachRecursive(

        if( ! (nStateSet & AccessibleStateType::MANAGES_DESCENDANTS) )
        {
            sal_Int64 n, nmax = xContext->getAccessibleChildCount();
            for( n = 0; n < nmax; n++ )
            {
                Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
            try {
                sal_Int64 n, nmax = xContext->getAccessibleChildCount();
                for( n = 0; n < nmax; n++ )
                {
                    Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );

                if( xChild.is() )
                    attachRecursive(xChild);
                    if( xChild.is() )
                        attachRecursive(xChild);
                }
            }
            catch (const IndexOutOfBoundsException&)
            {
                SAL_WARN("vcl", "Accessible object index does not exist in parent");
            }
        }
    }
@@ -197,13 +209,19 @@ void DocumentFocusListener::detachRecursive(

        if( ! (nStateSet & AccessibleStateType::MANAGES_DESCENDANTS) )
        {
            sal_Int64 n, nmax = xContext->getAccessibleChildCount();
            for( n = 0; n < nmax; n++ )
            {
                Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
            try {
                sal_Int64 n, nmax = xContext->getAccessibleChildCount();
                for( n = 0; n < nmax; n++ )
                {
                    Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );

                if( xChild.is() )
                    detachRecursive(xChild);
                    if( xChild.is() )
                        detachRecursive(xChild);
                }
            }
            catch (const IndexOutOfBoundsException&)
            {
                SAL_WARN("vcl", "Accessible object index does not exist in parent");
            }
        }
    }