[orca] Web: Ensure figcaptions and descendants are presented only once



commit 48ecad4aa8de7d047b7a9efa2317153312057982
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Mon Feb 8 16:10:10 2021 +0100

    Web: Ensure figcaptions and descendants are presented only once
    
    * Fix bug causing them to be skipped over in SayAll because they
      are labelling content.
    * Don't repeat the name of the figure when the first thing being
      presented is the caption from which the figure's name derives.

 src/orca/scripts/web/script.py           |  9 +++++---
 src/orca/scripts/web/script_utilities.py | 36 +++++++++++++++++++++-----------
 src/orca/scripts/web/speech_generator.py | 11 +++++++---
 src/orca/speech_generator.py             |  3 ++-
 4 files changed, 40 insertions(+), 19 deletions(-)
---
diff --git a/src/orca/scripts/web/script.py b/src/orca/scripts/web/script.py
index bb3130861..f1eaf247b 100644
--- a/src/orca/scripts/web/script.py
+++ b/src/orca/scripts/web/script.py
@@ -623,15 +623,18 @@ class Script(default.Script):
             else:
                 contents = self.utilities.getLineContentsAtOffset(obj, characterOffset)
             self._sayAllContents = contents
-            for content in contents:
+            for i, content in enumerate(contents):
+                obj, startOffset, endOffset, text = content
+                msg = "WEB SAY ALL CONTENT: %i. %s '%s' (%i-%i)" % (i, obj, text, startOffset, endOffset)
+                debug.println(debug.LEVEL_INFO, msg, True)
+
                 if self.utilities.isInferredLabelForContents(content, contents):
                     continue
 
-                obj, startOffset, endOffset, text = content
                 if startOffset == endOffset:
                     continue
 
-                if self.utilities.isLabellingContents(obj):
+                if self.utilities.isLabellingInteractiveElement(obj):
                     continue
 
                 if self.utilities.isLinkAncestorOfImageInContents(obj, contents):
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index b3c2bea9e..0f801e898 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -3225,16 +3225,7 @@ class Utilities(script_utilities.Utilities):
 
         return False
 
-    def labelTargets(self, obj):
-        if not (obj and self.inDocumentContent(obj)):
-            return []
-
-        rv = self._labelTargets.get(hash(obj))
-        if rv is not None:
-            return rv
-
-        rv = []
-
+    def targetsForLabel(self, obj):
         isLabel = lambda r: r.getRelationType() == pyatspi.RELATION_LABEL_FOR
         try:
             relations = list(filter(isLabel, obj.getRelationSet()))
@@ -3254,7 +3245,17 @@ class Utilities(script_utilities.Utilities):
             debug.println(debug.LEVEL_INFO, msg, True)
             rv.remove(obj)
 
-        rv = [hash(x) for x in rv if x is not None]
+        return list(filter(lambda x: x is not None, rv))
+
+    def labelTargets(self, obj):
+        if not (obj and self.inDocumentContent(obj)):
+            return []
+
+        rv = self._labelTargets.get(hash(obj))
+        if rv is not None:
+            return rv
+
+        rv = [hash(t) for t in self.targetsForLabel(obj)]
         self._labelTargets[hash(obj)] = rv
         return rv
 
@@ -3283,6 +3284,17 @@ class Utilities(script_utilities.Utilities):
 
         return None
 
+    def isLabellingInteractiveElement(self, obj):
+        if self._labelTargets.get(hash(obj)) == []:
+            return False
+
+        targets = self.targetsForLabel(obj)
+        for target in targets:
+            if target.getState().contains(pyatspi.STATE_FOCUSABLE):
+                return True
+
+        return False
+
     def isLabellingContents(self, obj, contents=[]):
         if self.isFocusModeWidget(obj):
             return False
@@ -3670,7 +3682,7 @@ class Utilities(script_utilities.Utilities):
         return 'feed' in self._getXMLRoles(obj)
 
     def isFigure(self, obj):
-        return 'figure' in self._getXMLRoles(obj)
+        return 'figure' in self._getXMLRoles(obj) or self._getTag(obj) == 'figure'
 
     def isLandmark(self, obj):
         if not (obj and self.inDocumentContent(obj)):
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index e559840c8..bf1d51304 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -362,6 +362,14 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
            and not args.get('inFlatReview'):
             return []
 
+        if self._script.utilities.isFigure(obj) and args.get('ancestorOf'):
+            caption = args.get('ancestorOf')
+            if caption.getRole() != pyatspi.ROLE_CAPTION:
+                isCaption = lambda x: x and x.getRole() == pyatspi.ROLE_CAPTION
+                caption = pyatspi.findAncestor(caption, isCaption)
+            if caption and hash(obj) in self._script.utilities.labelTargets(caption):
+                return []
+
         role = args.get('role', obj.getRole())
 
         # TODO - JD: Once the formatting strings are vastly cleaned up
@@ -763,9 +771,6 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         if not 'priorObj' in args:
             args['priorObj'] = self._script.utilities.getPriorContext()[0]
 
-        if self._script.utilities.isLabellingContents(obj):
-            result = list(filter(lambda x: x, self.generateContext(obj, **args)))
-
         if not result:
             result = list(filter(lambda x: x, super().generateSpeech(obj, **args)))
 
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index f56fa55dd..50622736f 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -2116,7 +2116,8 @@ class SpeechGenerator(generator.Generator):
             presentedRoles.append(altRole)
             count = ancestorRoles.count(altRole)
             self._overrideRole(altRole, args)
-            result.append(self.generate(x, formatType='focused', role=altRole, leaving=leaving, count=count))
+            result.append(self.generate(x, formatType='focused', role=altRole, leaving=leaving, count=count,
+                                        ancestorOf=obj))
             self._restoreRole(altRole, args)
 
         if not leaving:


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