Index: test/keystrokes/firefox/label_guess_bugzilla_search.py
===================================================================
--- test/keystrokes/firefox/label_guess_bugzilla_search.py	(revision 4329)
+++ test/keystrokes/firefox/label_guess_bugzilla_search.py	(working copy)
@@ -112,7 +112,7 @@
     ["BRAILLE LINE:  'abiscan List'",
      "     VISIBLE:  'abiscan List', cursor=1",
      "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Component abiscan multi-select List with 1248 items'"]))
+     "SPEECH OUTPUT: 'Component: abiscan multi-select List with 1248 items'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -320,7 +320,7 @@
     ["BRAILLE LINE:  'contains Combo'",
      "     VISIBLE:  'contains Combo', cursor=1",
      "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'a commenter contains combo box'"]))
+     "SPEECH OUTPUT: 'contains combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -393,7 +393,7 @@
     ["BRAILLE LINE:  'contains Combo'",
      "     VISIBLE:  'contains Combo', cursor=1",
      "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'a commenter contains combo box'"]))
+     "SPEECH OUTPUT: 'contains combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -467,7 +467,7 @@
     ["BRAILLE LINE:  '[Bug creation] List'",
      "     VISIBLE:  '[Bug creation] List', cursor=1",
      "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Alias [Bug creation] multi-select List with 26 items'"]))
+     "SPEECH OUTPUT: 'where one or more of the following changed: [Bug creation] multi-select List with 26 items'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -556,7 +556,7 @@
     ["BRAILLE LINE:  '--- Combo --- Combo  $l Or Button'",
      "     VISIBLE:  '--- Combo --- Combo  $l Or Butto', cursor=1",
      "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Not (negate this whole chart) --- combo box'"]))
+     "SPEECH OUTPUT: '--- combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
Index: test/keystrokes/firefox/label_guess_entries.py
===================================================================
--- test/keystrokes/firefox/label_guess_entries.py	(revision 4329)
+++ test/keystrokes/firefox/label_guess_entries.py	(working copy)
@@ -115,7 +115,7 @@
      "     VISIBLE:  ' $l Too far away to be a label.', cursor=1",
      "BRAILLE LINE:  ' $l Too far away to be a label.'",
      "     VISIBLE:  ' $l Too far away to be a label.', cursor=1",
-     "SPEECH OUTPUT: 'Looking at what follows visually, I'm not sure what I would type/i.e. what the labels are. text'"]))
+     "SPEECH OUTPUT: 'text'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -135,8 +135,7 @@
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "Next form field", 
-    ["BUG? - Below is what we should be getting. We were accidentally getting this from guessLabelFromLine, but the guessed label isn't on this line and should be guessed by getLabelFromOtherLines",
-     "BRAILLE LINE:  ' $l'",
+    ["BRAILLE LINE:  ' $l'",
      "     VISIBLE:  ' $l', cursor=1",
      "BRAILLE LINE:  ' $l'",
      "     VISIBLE:  ' $l', cursor=1",
@@ -148,8 +147,7 @@
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "Next form field", 
-    ["BUG? - Below is what we should be getting. We were accidentally getting this from guessLabelFromLine, but the guessed label isn't on this line and should be guessed by getLabelFromOtherLines",
-     "BRAILLE LINE:  ' $l'",
+    ["BRAILLE LINE:  ' $l'",
      "     VISIBLE:  ' $l', cursor=1",
      "BRAILLE LINE:  ' $l'",
      "     VISIBLE:  ' $l', cursor=1",
@@ -161,8 +159,7 @@
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "Next form field", 
-    ["BUG? - Below is what we should be getting. We were accidentally getting this from guessLabelFromLine, but the guessed label isn't on this line and should be guessed by getLabelFromOtherLines",
-     "BRAILLE LINE:  ' $l'",
+    ["BRAILLE LINE:  ' $l'",
      "     VISIBLE:  ' $l', cursor=1",
      "BRAILLE LINE:  ' $l'",
      "     VISIBLE:  ' $l', cursor=1",
@@ -199,12 +196,11 @@
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "Next form field", 
-    ["BUG? - We're not guessing this correctly",
-     "BRAILLE LINE:  ' $l $l $l'",
+    ["BRAILLE LINE:  ' $l $l $l'",
      "     VISIBLE:  ' $l $l $l', cursor=7",
      "BRAILLE LINE:  ' $l $l $l'",
      "     VISIBLE:  ' $l $l $l', cursor=7",
-     "SPEECH OUTPUT: 'text'"]))
+     "SPEECH OUTPUT: 'Last name text'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -241,7 +237,7 @@
      "     VISIBLE:  ' $l $l $l', cursor=7",
      "BRAILLE LINE:  ' $l $l $l'",
      "     VISIBLE:  ' $l $l $l', cursor=7",
-     "SPEECH OUTPUT: 'Last text'"]))
+     "SPEECH OUTPUT: 'Last name text'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -364,7 +360,7 @@
      "     VISIBLE:  ' $l $l $l $l', cursor=10",
      "BRAILLE LINE:  ' $l $l $l $l'",
      "     VISIBLE:  ' $l $l $l $l', cursor=10",
-     "SPEECH OUTPUT: 'text'"]))
+     "SPEECH OUTPUT: 'patched image text'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -413,7 +409,7 @@
      "     VISIBLE:  ' $l $l $l $l', cursor=10",
      "BRAILLE LINE:  ' $l $l $l $l'",
      "     VISIBLE:  ' $l $l $l $l', cursor=10",
-     "SPEECH OUTPUT: 'text'"]))
+     "SPEECH OUTPUT: 'patched image text'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -463,7 +459,7 @@
      "     VISIBLE:  ' $l $l $l $l', cursor=10",
      "BRAILLE LINE:  ' $l $l $l $l'",
      "     VISIBLE:  ' $l $l $l $l', cursor=10",
-     "SPEECH OUTPUT: 'text'"]))
+     "SPEECH OUTPUT: 'patched image text'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
Index: src/orca/scripts/toolkits/Gecko/script.py
===================================================================
--- src/orca/scripts/toolkits/Gecko/script.py	(revision 4330)
+++ src/orca/scripts/toolkits/Gecko/script.py	(working copy)
@@ -3579,8 +3579,8 @@
         """
 
         newCell = None
-        text = None
-        extents = ()
+        text = ""
+        extents = (0, 0, 0, 0)
         isField = False
         if not cell or cell.getRole() != pyatspi.ROLE_TABLE_CELL:
             return [newCell, text, extents, isField]
@@ -3602,13 +3602,22 @@
             nextCell = (row + rowspan, col)
         if nextCell:
             newCell = table.getAccessibleAt(nextCell[0], nextCell[1])
-            if newCell:
-                [obj, offset] = self.findFirstCaretContext(newCell, 0)
-                extents = self.getExtents(obj, offset, offset + 1)
-                isField = self.isFormField(obj)
-                if self.queryNonEmptyText(obj) \
-                   and not self.isBlankCell(newCell):
-                    text = self.getDisplayedText(obj)
+            objects = self.getObjectsFromEOCs(newCell, 0)
+            if len(objects):
+                extents = self.getExtents(objects[0][0], 
+                                          objects[0][1],
+                                          objects[0][2])
+            for obj in objects:
+                if obj[0].getRole() == pyatspi.ROLE_IMAGE:
+                    text += obj[0].name
+                elif not self.isFormField(obj[0]):
+                    text += obj[3]
+                else:
+                    isField = True
+                    text = ""
+                    exts = obj[0].queryComponent().getExtents(0)
+                    extents = [exts.x, exts.y, exts.width, exts.height]
+                    break
 
         return [newCell, text, extents, isField]
 
@@ -3924,35 +3933,31 @@
             [prevObj, prevOffset] = self.findPreviousLine(obj, 0, False)
             prevLineContents = self.getLineContentsAtOffset(prevObj,
                                                             prevOffset)
-            self._previousLineContents = prevLineContents
 
-        nextLineContents = self._nextLineContents
-        if index > 0 and nextLineContents:
-            nextObj = nextLineContents[0][0]
-            nextOffset = nextLineContents[0][1]
-
         # The labels for combo boxes won't be found below the combo box
         # because expanding the combo box will cover up the label. Labels
         # for lists probably won't be below the list either.
         #
-        if not nextLineContents and obj.getRole() in [pyatspi.ROLE_COMBO_BOX,
-                                                      pyatspi.ROLE_MENU,
-                                                      pyatspi.ROLE_MENU_ITEM,
-                                                      pyatspi.ROLE_LIST,
-                                                      pyatspi.ROLE_LIST_ITEM]:
-            [nextObj, nextOffset] = self.findNextLine(obj, 0, False)
-            nextLineContents = self.getLineContentsAtOffset(nextObj,
-                                                            nextOffset)
-            self._nextLineContents = nextLineContents
-        else:
+        if obj.getRole() in [pyatspi.ROLE_COMBO_BOX,
+                             pyatspi.ROLE_MENU,
+                             pyatspi.ROLE_MENU_ITEM,
+                             pyatspi.ROLE_LIST,
+                             pyatspi.ROLE_LIST_ITEM]:
             [nextObj, nextOffset] = [None, 0]
             nextLineContents = []
-
+        else:
+            nextLineContents = self._nextLineContents
+            if index > 0 and nextLineContents:
+                nextObj = nextLineContents[0][0]
+                nextOffset = nextLineContents[0][1]
+            else:
+                [nextObj, nextOffset] = self.findNextLine(obj, 0, False)
+                nextLineContents = self.getLineContentsAtOffset(nextObj,
+                                                                nextOffset)
         above = None
+        lastExtents = (0, 0, 0, 0)
         for content in prevLineContents:
-            extents = content[0].queryComponent().getExtents(0)
-            aboveExtents = \
-                 [extents.x, extents.y, extents.width, extents.height]
+            aboveExtents = self.getExtents(content[0], content[1], content[2])
 
             # [[[TODO: Grayed out buttons don't pass the isFormField()
             # test because they are neither focusable nor showing -- and
@@ -3967,21 +3972,6 @@
                                                     pyatspi.ROLE_MENU_ITEM,
                                                     pyatspi.ROLE_LIST]
 
-            # [[[TODO - JD: Nearby text that's not actually in the form
-            # may need to be ignored.  Let's do so unless it's directly
-            # above the form field or the text above is contained in the
-            # form's parent and adjust based on feedback, testing.]]]
-            #
-            theForm = self.getAncestor(obj,
-                                       [pyatspi.ROLE_FORM],
-                                       [pyatspi.ROLE_DOCUMENT_FRAME])
-            aboveForm = self.getAncestor(obj,
-                                         [pyatspi.ROLE_FORM],
-                                         [pyatspi.ROLE_DOCUMENT_FRAME])
-            aboveIsInForm = self.isSameObject(theForm, aboveForm)
-            formIsInAbove = theForm \
-                            and self.isSameObject(theForm.parent, content[0])
-
             # If the horizontal starting point of the object is the
             # same as the horizontal starting point of the text
             # above it, the text above it is probably serving as the
@@ -3992,27 +3982,33 @@
             # For an example of the latter case, see Bugzilla's Advanced
             # search page, Bug Changes section.
             #
-            if (objExtents != aboveExtents) and not aboveIsFormField:
-                guessThis = (0 <= abs(objExtents[0] - aboveExtents[0]) <= 2)
-                if not guessThis:
-                    objEnd = objExtents[0] + objExtents[2]
-                    aboveEnd = aboveExtents[0] + aboveExtents[2]
-                    guessThis = (0 <= objExtents[0] - aboveExtents[0] <= 50) \
-                                 and (aboveEnd > objEnd) \
-                                 and (aboveIsInForm or formIsInAbove)
-
-                if guessThis:
-                    above = content[0]
-                    guessAbove = self.expandEOCs(content[0],
-                                                 content[1],
-                                                 content[2])
+            if not above:
+                if (objExtents != aboveExtents) and not aboveIsFormField:
+                    xDiff = objExtents[0] - aboveExtents[0]
+                    guessThis = (0 <= abs(xDiff) <= 2)
+                    if not guessThis and (0 <= xDiff <= 50):
+                        guessThis = \
+                            (aboveExtents[0] + aboveExtents[2] > objExtents[0])
+                    if guessThis:
+                        above = content[0]
+                        guessAbove = content[3]
+            else:
+                # The "label" might be comprised of several objects (e.g.
+                # text with links).
+                #
+                lastEnd = lastExtents[0] + lastExtents[2]
+                if lastEnd - aboveExtents[0] < 10 and not aboveIsFormField:
+                    guessAbove += content[3]
+                else:
                     break
 
+            lastExtents = aboveExtents
+
         below = None
+        lastExtents = (0, 0, 0, 0)
         for content in nextLineContents:
-            extents = content[0].queryComponent().getExtents(0)
-            belowExtents = \
-                 [extents.x, extents.y, extents.width, extents.height]
+            belowExtents = self.getExtents(content[0], content[1], content[2])
+
             # [[[TODO: Grayed out buttons don't pass the isFormField()
             # test because they are neither focusable nor showing -- and
             # thus something we don't want to navigate to via structural
@@ -4026,29 +4022,28 @@
                                                     pyatspi.ROLE_MENU_ITEM,
                                                     pyatspi.ROLE_LIST]
 
-            # [[[TODO - JD: Nearby text that's not actually in the form
-            # may need to be ignored.  Let's try that for now and adjust
-            # based on feedback and testing.]]]
-            #
-            belowIsInForm = self.getAncestor(content[0],
-                                             [pyatspi.ROLE_FORM],
-                                             [pyatspi.ROLE_DOCUMENT_FRAME])
-
             # If the horizontal starting point of the object is the
             # same as the horizontal starting point of the text
             # below it, the text below it is probably serving as the
             # label. We'll allow for a 2 pixel difference.
             #
-            if objExtents != belowExtents \
-               and not belowIsFormField \
-               and belowIsInForm \
-               and 0 <= abs(objExtents[0] - belowExtents[0]) <= 2:
-                below = content[0]
-                guessBelow = self.expandEOCs(content[0],
-                                             content[1],
-                                             content[2])
-                break
+            if not below:
+                if (objExtents != belowExtents) and not belowIsFormField \
+                   and 0 <= abs(objExtents[0] - belowExtents[0]) <= 2:
+                    below = content[0]
+                    guessBelow = content[3]
+            else:
+                # The "label" might be comprised of several objects (e.g.
+                # text with links).
+                #
+                lastEnd = lastExtents[0] + lastExtents[2]
+                if lastEnd - belowExtents[0] < 10 and not belowIsFormField:
+                    guessBelow += content[3]
+                else:
+                    break
 
+            lastExtents = aboveExtents
+
         if above:
             if not below:
                 guess = guessAbove
@@ -4100,34 +4095,40 @@
         # testing "in the wild."
         #
         guess = None
-        extents = obj.queryComponent().getExtents(0)
-        objExtents = [extents.x, extents.y, extents.width, extents.height]
-        containingCell = \
-                       self.getAncestor(obj,
-                                        [pyatspi.ROLE_TABLE_CELL],
-                                        [pyatspi.ROLE_DOCUMENT_FRAME])
 
-        # If we're not in a table cell, pursuing this further is silly. If
-        # we're in a table cell but are not the sole occupant of that cell,
-        # we're likely in a more complex layout table than this approach
-        # can handle.
+        # If we're not the sole occupant of a table cell, we're either
+        # not in a table at all or are in a more complex layout table
+        # than this approach can handle.
         #
-        if not containingCell \
-           or (containingCell.childCount > 1):
+        containingCell = self.getAncestor(obj,
+                                          [pyatspi.ROLE_TABLE_CELL],
+                                          [pyatspi.ROLE_DOCUMENT_FRAME])
+        if not containingCell or containingCell.childCount > 1:
             return guess
-        elif self.getAncestor(obj,
-                              [pyatspi.ROLE_PARAGRAPH],
-                              [pyatspi.ROLE_TABLE,
-                               pyatspi.ROLE_DOCUMENT_FRAME]):
-            return guess
 
+        extents = obj.queryComponent().getExtents(0)
+        objExtents = [extents.x, extents.y, extents.width, extents.height]
+
         [cellLeft, leftText, leftExtents, leftIsField] = \
                    self.getNextCellInfo(containingCell, "left")
         [cellRight, rightText, rightExtents, rightIsField] = \
                    self.getNextCellInfo(containingCell, "right")
         [cellAbove, aboveText, aboveExtents, aboveIsField] = \
                    self.getNextCellInfo(containingCell, "up")
-        [cellBelow, belowText, belowExtents, belowIsField] = \
+
+        # The labels for combo boxes won't be found below the combo box
+        # because expanding the combo box will cover up the label. Labels
+        # for lists probably won't be below the list either.
+        #
+        if obj.getRole() in [pyatspi.ROLE_COMBO_BOX,
+                             pyatspi.ROLE_MENU,
+                             pyatspi.ROLE_MENU_ITEM,
+                             pyatspi.ROLE_LIST,
+                             pyatspi.ROLE_LIST_ITEM]:
+            [cellBelow, belowText, belowExtents, belowIsField] = \
+                    [None, "", (0, 0, 0, 0), False]
+        else:
+            [cellBelow, belowText, belowExtents, belowIsField] = \
                    self.getNextCellInfo(containingCell, "down")
 
         if rightText:
@@ -4168,32 +4169,20 @@
             # if the form fields above us are all of the same type
             # and size (say, within 1 pixel).
             #
-            grid = False
-            done = False
             nextCell = containingCell
-            while not done:
+            while nextCell:
                 [nextCell, text, extents, isField] = \
                         self.getNextCellInfo(nextCell, "up")
                 if nextCell:
                     dWidth = abs(objExtents[2] - extents[2])
                     dHeight = abs(objExtents[3] - extents[3])
-                    if dWidth > 1 or dHeight > 1:
-                        done = True
-                    if not isField:
-                        [row, col] = self.getCellCoordinates(nextCell)
-                        if row == 0:
-                            grid = True
-                            done = True
-                else:
-                    done = True
+                    if (dWidth > 1 or dHeight > 1):
+                        if not isField:
+                            [row, col] = self.getCellCoordinates(nextCell)
+                            if row == 0:
+                                guess = text
+                        break
 
-            if grid:
-                topCol = nextCell.parent.queryTable().getAccessibleAt(0, col)
-                [objTop, offset] = self.findFirstCaretContext(topCol, 0)
-                if self.queryNonEmptyText(topCol) \
-                   and not self.isFormField(topCol):
-                    guess = self.expandEOCs(topCol)
-
         return guess
 
     def guessTheLabel(self, obj, focusedOnly=True):
@@ -4233,6 +4222,9 @@
             if self.isSameObject(field, obj):
                 return label
 
+        parent = obj.parent
+        text = self.queryNonEmptyText(parent)
+
         # Because the guesswork is based upon spatial relations, if we're
         # in a list, look from the perspective of the first list item rather
         # than from the list as a whole.
@@ -4249,10 +4241,14 @@
             # print "guess from table: ", guess
         if not guess:
             # Maybe the text is above or below us, but not in a table
-            # cell.
+            # cell -- or in a table cell which contains multiple items
+            # and/or line breaks.
             #
-            guess = self.guessLabelFromOtherLines(obj)
-            #print "guess from other lines: ", guess
+            if parent.getRole() != pyatspi.ROLE_TABLE_CELL \
+               or parent.childCount > 1 \
+               or (text and text.getText(0, -1).find("\n") >= 0):
+                guess = self.guessLabelFromOtherLines(obj)
+                #print "guess from other lines: ", guess
         if not guess:
             # We've pretty much run out of options.  From Tom's overview
             # of the approach for all controls:
