[orca] Handle (un)ordered lists in which item text falls outside the item element



commit c94b66e44715c04d3b6ca7038f86c90bd4ba146e
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Wed Oct 26 15:05:45 2016 -0400

    Handle (un)ordered lists in which item text falls outside the item element

 src/orca/scripts/web/braille_generator.py          |    2 +-
 src/orca/scripts/web/script_utilities.py           |   17 +++--
 src/orca/scripts/web/speech_generator.py           |    2 +-
 test/html/broken-list.html                         |   12 +++
 .../keystrokes/firefox/line_nav_broken_list.params |    1 +
 test/keystrokes/firefox/line_nav_broken_list.py    |   80 ++++++++++++++++++++
 6 files changed, 105 insertions(+), 9 deletions(-)
---
diff --git a/src/orca/scripts/web/braille_generator.py b/src/orca/scripts/web/braille_generator.py
index b301bdb..cdca9c3 100644
--- a/src/orca/scripts/web/braille_generator.py
+++ b/src/orca/scripts/web/braille_generator.py
@@ -164,7 +164,7 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
         elif self._script.utilities.isStatic(obj) \
              or self._script.utilities.isAnchor(obj):
             oldRole = self._overrideRole('ROLE_STATIC', args)
-        elif self._script.utilities.treatAsDiv(obj):
+        elif self._script.utilities.treatAsDiv(obj, offset=args.get('startOffset')):
             oldRole = self._overrideRole(pyatspi.ROLE_SECTION, args)
 
         if obj.getRole() == pyatspi.ROLE_MENU_ITEM:
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index bbbe82c..68707a4 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -1598,14 +1598,10 @@ class Utilities(script_utilities.Utilities):
 
         return string, start, end
 
-    def treatAsDiv(self, obj):
+    def treatAsDiv(self, obj, offset=None):
         if not (obj and self.inDocumentContent(obj)):
             return False
 
-        rv = self._treatAsDiv.get(hash(obj))
-        if rv is not None:
-            return rv
-
         try:
             role = obj.getRole()
             childCount = obj.childCount
@@ -1614,7 +1610,14 @@ class Utilities(script_utilities.Utilities):
             debug.println(debug.LEVEL_INFO, msg, True)
             return False
 
-        rv = False
+        if role == pyatspi.ROLE_LIST and offset is not None:
+            string = self.substring(obj, offset, offset + 1)
+            if string and string != self.EMBEDDED_OBJECT_CHARACTER:
+                return True
+
+        rv = self._treatAsDiv.get(hash(obj))
+        if rv is not None:
+            return rv
 
         validRoles = self._validChildRoles.get(role)
         if validRoles:
@@ -3074,7 +3077,7 @@ class Utilities(script_utilities.Utilities):
                        pyatspi.ROLE_INTERNAL_FRAME,
                        pyatspi.ROLE_TABLE,
                        pyatspi.ROLE_TABLE_ROW]
-        if role in lookInChild and obj.childCount and not self.treatAsDiv(obj):
+        if role in lookInChild and obj.childCount and not self.treatAsDiv(obj, offset):
             msg = "WEB: First caret context for %s, %i will look in child %s" % (obj, offset, obj[0])
             debug.println(debug.LEVEL_INFO, msg, True)
             return self.findFirstCaretContext(obj[0], 0)
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index 5fd92a4..38916c1 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -460,7 +460,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
             oldRole = self._overrideRole(pyatspi.ROLE_LINK, args)
         elif self._script.utilities.isAnchor(obj):
             oldRole = 'ROLE_STATIC'
-        elif self._script.utilities.treatAsDiv(obj):
+        elif self._script.utilities.treatAsDiv(obj, offset=args.get('startOffset')):
             oldRole = self._overrideRole(pyatspi.ROLE_SECTION, args)
         else:
             oldRole = self._overrideRole(self._getAlternativeRole(obj, **args), args)
diff --git a/test/html/broken-list.html b/test/html/broken-list.html
new file mode 100644
index 0000000..99989bb
--- /dev/null
+++ b/test/html/broken-list.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<p>line 1</p>
+<ol>
+<li>item</li>
+<li><a href="foo">item</a></li> not item
+<li>item</li>
+</ol>
+</body>
+</html>
+
diff --git a/test/keystrokes/firefox/line_nav_broken_list.params 
b/test/keystrokes/firefox/line_nav_broken_list.params
new file mode 100644
index 0000000..bc97d6b
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_broken_list.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/broken-list.html
diff --git a/test/keystrokes/firefox/line_nav_broken_list.py b/test/keystrokes/firefox/line_nav_broken_list.py
new file mode 100644
index 0000000..80b4da7
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_broken_list.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+#sequence.append(WaitForDocLoad())
+sequence.append(PauseAction(5000))
+
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+sequence.append(PauseAction(3000))
+
+sequence.append(KeyComboAction("<Control>Home"))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Line Down",
+    ["BRAILLE LINE:  '1. item'",
+     "     VISIBLE:  '1. item', cursor=1",
+     "SPEECH OUTPUT: '1. item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(PauseAction(1000))
+sequence.append(utils.AssertPresentationAction(
+    "2. Line Down",
+    ["BRAILLE LINE:  '2. item'",
+     "     VISIBLE:  '2. item', cursor=1",
+     "SPEECH OUTPUT: '2.'",
+     "SPEECH OUTPUT: 'item'",
+     "SPEECH OUTPUT: 'link.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "3. Line Down",
+    ["BRAILLE LINE:  'not item'",
+     "     VISIBLE:  'not item', cursor=1",
+     "SPEECH OUTPUT: 'not item'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Down",
+    ["BRAILLE LINE:  '3. item'",
+     "     VISIBLE:  '3. item', cursor=1",
+     "SPEECH OUTPUT: '3. item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "5. Line Up",
+    ["BRAILLE LINE:  'not item'",
+     "     VISIBLE:  'not item', cursor=1",
+     "SPEECH OUTPUT: 'not item'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "6. Line Up",
+    ["BRAILLE LINE:  '2. item'",
+     "     VISIBLE:  '2. item', cursor=1",
+     "SPEECH OUTPUT: '2.'",
+     "SPEECH OUTPUT: 'item'",
+     "SPEECH OUTPUT: 'link.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "7. Line Up",
+    ["BRAILLE LINE:  '1. item'",
+     "     VISIBLE:  '1. item', cursor=1",
+     "SPEECH OUTPUT: '1. item.'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()


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