[orca/gnome-3-14] More work on attempting to handle the destruction of focused Gecko elements



commit ec7505bc0cc02a87123bda977689c6249b851b71
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Mon Sep 15 20:35:07 2014 -0400

    More work on attempting to handle the destruction of focused Gecko elements

 src/orca/script_utilities.py                       |   36 ++++++++++----
 src/orca/scripts/toolkits/Gecko/script.py          |    8 ++-
 .../scripts/toolkits/Gecko/script_utilities.py     |   34 +++++++++++++
 test/harness/runall.sh                             |    2 +-
 ...on-in-link-with-position-relative-on-focus.html |   18 +++++++
 ...utton_in_link_position_relative_on_focus.params |    1 +
 ...av_button_in_link_position_relative_on_focus.py |   51 ++++++++++++++++++++
 7 files changed, 137 insertions(+), 13 deletions(-)
---
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index a6b7382..ebd8faa 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -873,6 +873,30 @@ class Utilities:
 
         return readOnly
 
+    def _hasSamePath(self, obj1, obj2):
+        path1 = pyatspi.utils.getPath(obj1)
+        path2 = pyatspi.utils.getPath(obj2)
+        if len(path1) != len(path2):
+            return False
+
+        # The first item in all paths, even valid ones, is -1.
+        path1 = path1[1:]
+        path2 = path2[1:]
+
+        # If both have invalid child indices, all bets are off.
+        if path1.count(-1) and path2.count(-1):
+            return False
+
+        try:
+            index = path1.index(-1)
+        except ValueError:
+            try:
+                index = path2.index(-1)
+            except ValueError:
+                index = len(path2)
+
+        return path1[0:index] == path2[0:index]
+
     def isSameObject(self, obj1, obj2):
         if (obj1 == obj2):
             return True
@@ -882,17 +906,9 @@ class Utilities:
         try:
             if (obj1.name != obj2.name) or (obj1.getRole() != obj2.getRole()):
                 return False
+            if self._hasSamePath(obj1, obj2):
+                return True
             else:
-                # If one of the objects was destroyed, the last index may be -1.
-                # In addition, the extents likely will be zeroed out so the next
-                # tests will fail. But if the rest of the path is the same and
-                # the names are the same and the roles are the same, let's cross
-                # our fingers and call them the same.
-                path1 = pyatspi.utils.getPath(obj1)
-                path2 = pyatspi.utils.getPath(obj2)
-                if path1[0:-1] == path2[0:-1] and obj1.name == obj2.name != "":
-                    return True
-
                 # Comparing the extents of objects which claim to be different
                 # addresses both managed descendants and implementations which
                 # recreate accessibles for the same widget.
diff --git a/src/orca/scripts/toolkits/Gecko/script.py b/src/orca/scripts/toolkits/Gecko/script.py
index 038b6b0..71e9b42 100644
--- a/src/orca/scripts/toolkits/Gecko/script.py
+++ b/src/orca/scripts/toolkits/Gecko/script.py
@@ -1086,9 +1086,13 @@ class Script(default.Script):
         # Gecko to kill the accessible object that we just moved to and create
         # a new object to replace it. If we don't catch this, navigation breaks
         # because the proverbial rug has just been pulled out from under us. :(
+        # To make matters worse, the replacement object can be in the ancestry.
         obj, offset = self.getCaretContext()
-        if self.utilities.isSameObject(event.any_data, obj):
-            self.setCaretContext(event.any_data, offset)
+        if obj and self.utilities.isZombie(obj):
+            replicant = self.utilities.findReplicant(event.any_data, obj)
+            if replicant:
+                self.setCaretPosition(replicant, offset)
+                return
 
         if self.handleAsLiveRegion(event):
             self.liveMngr.handleEvent(event)
diff --git a/src/orca/scripts/toolkits/Gecko/script_utilities.py 
b/src/orca/scripts/toolkits/Gecko/script_utilities.py
index 273c4f1..38a4a7c 100644
--- a/src/orca/scripts/toolkits/Gecko/script_utilities.py
+++ b/src/orca/scripts/toolkits/Gecko/script_utilities.py
@@ -989,3 +989,37 @@ class Utilities(script_utilities.Utilities):
                 return True
 
         return False
+
+    def isZombie(self, obj):
+        try:
+            index = obj.getIndexInParent()
+            state = obj.getState()
+        except:
+            debug.println(debug.LEVEL_INFO, "ZOMBIE: %s is null or dead" % obj)
+            return True
+
+        if obj.getIndexInParent() == -1:
+            debug.println(debug.LEVEL_INFO, "ZOMBIE: %s's index is -1" % obj)
+            return True
+        if state.contains(pyatspi.STATE_DEFUNCT):
+            debug.println(debug.LEVEL_INFO, "ZOMBIE: %s is defunct" % obj)
+            return True
+        if state.contains(pyatspi.STATE_INVALID):
+            debug.println(debug.LEVEL_INFO, "ZOMBIE: %s is invalid" % obj)
+            return True
+
+        return False
+
+    def findReplicant(self, root, obj):
+        if not (root and obj):
+            return None
+
+        isSame = lambda x: x and self.isSameObject(x, obj)
+        if isSame(root):
+            replicant = root
+        else:
+            replicant = pyatspi.utils.findDescendant(root, isSame)
+
+        msg = "HACK: Returning %s as replicant for Zombie %s" % (replicant, obj)
+        debug.println(debug.LEVEL_INFO, msg)
+        return replicant
diff --git a/test/harness/runall.sh b/test/harness/runall.sh
index 470bc83..b35036a 100755
--- a/test/harness/runall.sh
+++ b/test/harness/runall.sh
@@ -167,7 +167,7 @@ do
       #
       mkdir -p ./tmp/$application
       cd ./tmp/$application
-      for testFile in `find $testDir -xtype f -name "*.py" | sort`; do
+      for testFile in `find $testDir -xtype f -name "aria*.py" | sort`; do
         echo ========================================
         echo Running $testFile
         if [ "$found" -gt 0 ]
diff --git a/test/html/button-in-link-with-position-relative-on-focus.html 
b/test/html/button-in-link-with-position-relative-on-focus.html
new file mode 100644
index 0000000..b37d159
--- /dev/null
+++ b/test/html/button-in-link-with-position-relative-on-focus.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+<style>
+a:focus{position:relative;}
+button span{display:block;}
+button{display:inline-block;)
+</style>   
+</head>
+<body>
+<p>Start</p>
+<div>
+<p>Line 1</p>
+<a href="foo"><button><span>&nbsp; Line 2 &nbsp;</span></button></a> &nbsp;&nbsp;
+<p>Line 3</p>
+</div>
+<p>End</p>
+</body>
+</html>
diff --git a/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.params 
b/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.params
new file mode 100644
index 0000000..fcdb529
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/button-in-link-with-position-relative-on-focus.html
diff --git a/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py 
b/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py
new file mode 100644
index 0000000..d735dc0
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+sequence.append(KeyComboAction("<Control>Home"))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Top of file",
+    ["BRAILLE LINE:  'Line 1'",
+     "     VISIBLE:  'Line 1', cursor=1",
+     "SPEECH OUTPUT: 'Line 1'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "2. Line Down",
+    ["BRAILLE LINE:  '  Line 2  '",
+     "     VISIBLE:  '  Line 2  ', cursor=1",
+     "SPEECH OUTPUT: 'Line 2'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "3. Line Down",
+    ["BRAILLE LINE:  'Line 3'",
+     "     VISIBLE:  'Line 3', cursor=1",
+     "SPEECH OUTPUT: 'Line 3'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Up",
+    ["BRAILLE LINE:  '  Line 2  '",
+     "     VISIBLE:  '  Line 2  ', cursor=1",
+     "SPEECH OUTPUT: 'Line 2'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "5. Line Up",
+    ["BRAILLE LINE:  'Line 1'",
+     "     VISIBLE:  'Line 1', cursor=1",
+     "SPEECH OUTPUT: 'Line 1'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]