Index: test/keystrokes/firefox/bug_544771.py
===================================================================
--- test/keystrokes/firefox/bug_544771.py	(revision 4449)
+++ test/keystrokes/firefox/bug_544771.py	(working copy)
@@ -67,7 +67,9 @@
 sequence.append(utils.AssertPresentationAction(
     "3. Return", 
     ["BRAILLE LINE:  ''",
-     "     VISIBLE:  '', cursor=1"]))
+     "     VISIBLE:  '', cursor=1",
+     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'link'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
Index: test/keystrokes/firefox/bug_568631.py
===================================================================
--- test/keystrokes/firefox/bug_568631.py	(revision 0)
+++ test/keystrokes/firefox/bug_568631.py	(revision 0)
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/python
+
+"""Test of navigation by same-page links on the Orca wiki."""
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+########################################################################
+# We wait for the focus to be on a blank Firefox window.
+#
+sequence.append(WaitForWindowActivate(utils.firefoxFrameNames, None))
+
+########################################################################
+# Load the local "wiki" test case.
+#
+sequence.append(KeyComboAction("<Control>l"))
+sequence.append(WaitForFocus(acc_role=pyatspi.ROLE_ENTRY))
+
+sequence.append(TypeAction(utils.htmlURLPrefix + "orca-wiki.html"))
+sequence.append(KeyComboAction("Return"))
+
+sequence.append(WaitForDocLoad())
+
+sequence.append(WaitForFocus("Orca - GNOME Live!",
+                             acc_role=pyatspi.ROLE_DOCUMENT_FRAME))
+
+sequence.append(PauseAction(6000))
+
+########################################################################
+# Press Control+Home to move to the top.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("<Control>Home"))
+sequence.append(utils.AssertPresentationAction(
+    "Top of file", 
+    ["BRAILLE LINE:  'Home News Projects Art Support Development Community'",
+     "     VISIBLE:  'Home News Projects Art Support D', cursor=1",
+     "SPEECH OUTPUT: 'Home link News link Projects link Art link Support link Development link Community link'"]))
+
+########################################################################
+# Tab to the About link
+#
+for i in range(25):
+    sequence.append(KeyComboAction("Tab"))
+
+# Just a little extra wait to let some events get through.
+#
+sequence.append(PauseAction(5000))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+    "Tab", 
+    ["BRAILLE LINE:  '2. About",
+     "     VISIBLE:  '2. About', cursor=4",
+     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'About link'"]))
+
+########################################################################
+# Press Return to active the link
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Return", 1000))
+sequence.append(utils.AssertPresentationAction(
+    "Return",
+    ["BRAILLE LINE:  'About h1'",
+     "     VISIBLE:  'About h1', cursor=1",
+     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'About heading level 1'"]))
+
+########################################################################
+# Press Down Arrow to read the next line (verifying that the caret
+# position was correctly updated).
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "Line Down", 
+    ["BRAILLE LINE:  'Orca is a free, open source, flexible, extensible, and powerful assistive'",
+     "     VISIBLE:  'Orca is a free, open source, fle', cursor=1",
+     "SPEECH OUTPUT: 'Orca is a free, open source, flexible, extensible, and powerful assistive'"]))
+
+########################################################################
+# Move to the location bar by pressing Control+L.  When it has focus
+# type "about:blank" and press Return to restore the browser to the
+# conditions at the test's start.
+#
+sequence.append(KeyComboAction("<Control>l"))
+sequence.append(WaitForFocus(acc_role=pyatspi.ROLE_ENTRY))
+
+sequence.append(TypeAction("about:blank"))
+sequence.append(KeyComboAction("Return"))
+
+sequence.append(WaitForDocLoad())
+
+# Just a little extra wait to let some events get through.
+#
+sequence.append(PauseAction(3000))
+
+sequence.append(utils.AssertionSummaryAction())
+
+sequence.start()
Index: src/orca/scripts/toolkits/Gecko/script.py
===================================================================
--- src/orca/scripts/toolkits/Gecko/script.py	(revision 4449)
+++ src/orca/scripts/toolkits/Gecko/script.py	(working copy)
@@ -45,6 +45,7 @@
 import pyatspi
 import re
 import time
+import urlparse
 
 import orca.braille as braille
 import orca.debug as debug
@@ -1364,6 +1365,8 @@
             locusOfFocusState = pyatspi.StateSet()
             locusOfFocusState = locusOfFocusState.raw()
 
+        notifyPresentationManagers = False
+
         # Find out if the caret really moved. Firefox 3.1 gives us caret-moved
         # events when certain focusable objects first get focus. If we haven't
         # really moved, there's no point in updating braille again -- which is
@@ -1402,13 +1405,23 @@
                 if locusOfFocusRole == pyatspi.ROLE_IMAGE:
                     return
                 elif locusOfFocusRole == pyatspi.ROLE_LINK:
-                    # Be sure it's not a same-page link. We can detect them
-                    # because the anchor being moved to (and issuing the
-                    # event) is also of ROLE_LINK and has no text.
-                    #
-                    if eventSourceRole != pyatspi.ROLE_LINK \
-                       or self.queryNonEmptyText(event.source):
-                        return
+                    # Be sure it's not a same-page link. While such beasts
+                    # typically point to anchors, they can point to other
+                    # objects referencing them by name or ID. Therefore,
+                    # get the URI for the link of interest and parse it.
+                    # parsed URI is returned as a tuple containing six
+                    # components: 
+                    # scheme://netloc/path;parameters?query#fragment.
+                    try:
+                        uri = self.getURI(orca_state.locusOfFocus)
+                        uriInfo = urlparse.urlparse(uri)
+                    except:
+                        pass
+                    else:
+                        if uriInfo and not uriInfo[5]:
+                            return
+                        else:
+                            notifyPresentationManagers = True
                 elif eventSourceRole == pyatspi.ROLE_SECTION:
                     # Google Calendar's Day grid seems to issue these quite
                     # a bit. If we don't ignore them, we'll loop.
@@ -1462,7 +1475,11 @@
             [obj, characterOffset] = \
                 self.findFirstCaretContext(event.source, event.detail1)
             self.setCaretContext(obj, characterOffset)
-            orca.setLocusOfFocus(event, obj, False)
+            orca.setLocusOfFocus(event, obj, notifyPresentationManagers)
+            if notifyPresentationManagers:
+                # No point in double-brailling the locusOfFocus.
+                #
+                return
 
         # Pass the event along to the default script for processing.
         #
