[orca] Add support for speech presentation of embedded object characters in WebKitGtk content.



commit 72f8bcee3d1fc66309253ad8f780f0a96eebda12
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Sat Dec 3 18:45:45 2011 +0100

    Add support for speech presentation of embedded object characters in WebKitGtk content.

 src/orca/orca_gui_main.py                          |    2 +-
 src/orca/scripts/toolkits/WebKitGtk/script.py      |   72 +++++++++++++++-----
 .../scripts/toolkits/WebKitGtk/script_utilities.py |   58 +++++++++++++++-
 3 files changed, 113 insertions(+), 19 deletions(-)
---
diff --git a/src/orca/orca_gui_main.py b/src/orca/orca_gui_main.py
index a3f2d0d..72f696d 100644
--- a/src/orca/orca_gui_main.py
+++ b/src/orca/orca_gui_main.py
@@ -111,8 +111,8 @@ class OrcaMainGUI(Gtk.Window):
         # Translators: This text is used in the Orca About dialog.
         #
         copyrights = _("Copyright (c) 2010-2011 The Orca Team \n" \
+                       "Copyright (c) 2010-2011 Igalia, S.L. \n" \
                        "Copyright (c) 2010 Consorcio Fernando de los Rios \n" \
-                       "Copyright (c) 2010 Igalia, S.L. \n" \
                        "Copyright (c) 2010 Informal Informatica LTDA. \n" \
                        "Copyright (c) 2005-2010 Sun Microsystems Inc. \n" \
                        "Copyright (c) 2005-2008 Google Inc. \n" \
diff --git a/src/orca/scripts/toolkits/WebKitGtk/script.py b/src/orca/scripts/toolkits/WebKitGtk/script.py
index 4758746..ce2ac16 100644
--- a/src/orca/scripts/toolkits/WebKitGtk/script.py
+++ b/src/orca/scripts/toolkits/WebKitGtk/script.py
@@ -347,33 +347,73 @@ class Script(default.Script):
         """Speak the character at the caret.
 
         Arguments:
-        - obj: an Accessible object that implements the AccessibleText
-          interface
+        - obj: an Accessible object that implements the AccessibleText interface
         """
 
-        if obj.getRole() == pyatspi.ROLE_SEPARATOR:
-            speech.speak(self.speechGenerator.generateSpeech(obj))
-            return
+        boundary = pyatspi.TEXT_BOUNDARY_CHAR
+        objects = self.utilities.getObjectsFromEOCs(obj, boundary)
+        for (obj, start, end, string) in objects:
+            if string:
+                speech.speakCharacter(string)
+            else:
+                speech.speak(self.speechGenerator.generateSpeech(obj))
 
-        default.Script.sayCharacter(self, obj)
+    def sayWord(self, obj):
+        """Speaks the word at the caret.
+
+        Arguments:
+        - obj: an Accessible object that implements the AccessibleText interface
+        """
+
+        boundary = pyatspi.TEXT_BOUNDARY_WORD_START
+        objects = self.utilities.getObjectsFromEOCs(obj, boundary)
+        for (obj, start, end, string) in objects:
+            self.sayPhrase(obj, start, end)
 
     def sayLine(self, obj):
-        """Speaks the line of an AccessibleText object that contains the
-        caret.
+        """Speaks the line at the caret.
 
         Arguments:
-        - obj: an Accessible object that implements the AccessibleText
-               interface
+        - obj: an Accessible object that implements the AccessibleText interface
         """
 
-        default.Script.sayLine(self, obj)
+        boundary = pyatspi.TEXT_BOUNDARY_LINE_START
+        objects = self.utilities.getObjectsFromEOCs(obj, boundary)
+        for (obj, start, end, string) in objects:
+            self.sayPhrase(obj, start, end)
 
-        if obj.getRole() == pyatspi.ROLE_PANEL and obj.getIndexInParent() == 0:
-            obj = obj.parent
+            # TODO: Move these next items into the speech generator.
+            if obj.getRole() == pyatspi.ROLE_PANEL \
+               and obj.getIndexInParent() == 0:
+                obj = obj.parent
 
-        rolesToSpeak = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK]
-        if obj.getRole() in rolesToSpeak:
-            speech.speak(self.speechGenerator.getRoleName(obj))
+            rolesToSpeak = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK]
+            if obj.getRole() in rolesToSpeak:
+                speech.speak(self.speechGenerator.getRoleName(obj))
+
+    def sayPhrase(self, obj, startOffset, endOffset):
+        """Speaks the text of an Accessible object between the given offsets.
+
+        Arguments:
+        - obj: an Accessible object that implements the AccessibleText interface
+        - startOffset: the start text offset.
+        - endOffset: the end text offset.
+        """
+
+        phrase = self.utilities.substring(obj, startOffset, endOffset)
+        if len(phrase) and phrase != "\n":
+            if phrase.decode("UTF-8").isupper():
+                voice = self.voices[settings.UPPERCASE_VOICE]
+            else:
+                voice = self.voices[settings.DEFAULT_VOICE]
+
+            phrase = self.utilities.adjustForRepeats(phrase)
+            phrase = self.utilities.adjustForLinks(obj, phrase, startOffset)
+            speech.speak(phrase, voice)
+        else:
+            # Speak blank line if appropriate.
+            #
+            self.sayCharacter(obj)
 
     def skipObjectEvent(self, event):
         """Gives us, and scripts, the ability to decide an event isn't
diff --git a/src/orca/scripts/toolkits/WebKitGtk/script_utilities.py b/src/orca/scripts/toolkits/WebKitGtk/script_utilities.py
index 7cdde86..9979164 100644
--- a/src/orca/scripts/toolkits/WebKitGtk/script_utilities.py
+++ b/src/orca/scripts/toolkits/WebKitGtk/script_utilities.py
@@ -1,6 +1,9 @@
 # Orca
 #
-# Copyright 2010 Joanmarie Diggs.
+# Copyright (C) 2010 Joanmarie Diggs
+# Copyright (C) 2011 Igalia, S.L.
+#
+# Author: Joanmarie Diggs <jdiggs igalia com>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -20,12 +23,15 @@
 __id__ = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2010 Joanmarie Diggs."
+__copyright__ = "Copyright (c) 2010 Joanmarie Diggs." \
+                "Copyright (c) 2011 Igalia, S.L."
 __license__   = "LGPL"
 
 import pyatspi
+import re
 
 import orca.script_utilities as script_utilities
+import orca.settings as settings
 
 #############################################################################
 #                                                                           #
@@ -105,3 +111,51 @@ class Utilities(script_utilities.Utilities):
                 text = self.linkBasename(obj)
 
         return text
+
+    def getObjectsFromEOCs(self, obj, boundary=None, offset=None):
+        """Breaks the string containing a mixture of text and embedded object
+        characters into a list of (obj, startOffset, endOffset, string) tuples.
+
+        Arguments
+        - obj: the object whose EOCs we need to expand into tuples
+        - boundary: the pyatspi text boundary type. If None, get all text.
+        - offset: the character offset. If None, use the current offset.
+
+        Returns a list of (obj, startOffset, endOffset, string) tuples.
+        """
+
+        try:
+            text = obj.queryText()
+            htext = obj.queryHypertext()
+        except (AttributeError, NotImplementedError):
+            return [(obj, 0, 1, '')]
+
+        if offset == None:
+            offset = text.caretOffset
+        if boundary == None:
+            start = offset
+            end = text.characterCount
+            string = text.getText(start, end)
+        else:
+            if boundary == pyatspi.TEXT_BOUNDARY_CHAR:
+                key, mods = self.lastKeyAndModifiers()
+                if (mods & settings.SHIFT_MODIFIER_MASK) and key == 'Right':
+                    offset -= 1
+            string, start, end = text.getTextAtOffset(offset, boundary)
+
+        if not string:
+            return [(obj, 0, 1, '')]
+
+        string = string.decode('UTF-8')
+        pattern = re.compile(self.EMBEDDED_OBJECT_CHARACTER)
+        offsets = [m.start(0) for m in re.finditer(pattern, string)]
+        objects = \
+            [(o, obj[htext.getLinkIndex(o + start)], 0, 1, '') for o in offsets]
+
+        pattern = re.compile('[^%s]+' % self.EMBEDDED_OBJECT_CHARACTER)
+        spans = [m.span() for m in re.finditer(pattern, string)]
+        for (s1, s2) in spans:
+            objects.append([s1, obj, s1 + start, s2 + start, string[s1:s2]])
+
+        objects = sorted(objects, key=lambda x: x[0])
+        return map(lambda o: o[1:5], objects)



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