Index: src/orca/Gecko.py
===================================================================
--- src/orca/Gecko.py	(revision 3413)
+++ src/orca/Gecko.py	(working copy)
@@ -74,6 +74,11 @@
 #
 performanceEnhancements = True
 
+# Temporary debugging/testing setting.  If True, use the experimental
+# methods to find the next/previous line.
+#
+useNewLineNav = True
+
 # If True, it tells us to take over caret navigation.  This is something
 # that can be set in user-settings.py:
 #
@@ -4331,7 +4336,9 @@
         - offset: the offset within obj
         """
 
-        self._currentLineContents = self.getLineContentsAtOffset(obj, offset)
+        if not self._currentLineContents:
+            self._currentLineContents = self.getLineContentsAtOffset(obj,
+                                                                     offset)
         self.speakContents(self._currentLineContents)
         self.updateBraille(obj)
         self._currentLineContents = None
@@ -6397,8 +6404,14 @@
         if not obj or not self.inDocumentContent(obj):
             return [None, -1]
 
+        # We do not want to descend objects of certain role types.
+        #
+        doNotDescend = obj.getState().contains(pyatspi.STATE_FOCUSABLE) \
+                       and obj.getRole() in [pyatspi.ROLE_COMBO_BOX,
+                                             pyatspi.ROLE_LIST]
+
         text = self.queryNonEmptyText(obj)
-        if text and not (self.isAriaWidget(obj) 
+        if text and not (self.isAriaWidget(obj) \
                          and obj.getRole() == pyatspi.ROLE_LIST):
             unicodeText = self.getUnicodeText(obj)
 
@@ -6425,13 +6438,11 @@
                     nextOffset += 1
 
 
-        # If this is a list in an HTML form, we don't want to place the
-        # caret inside the list, but rather treat the list as a single
-        # object.  Otherwise, if it has children, look there.
+        # If this is a list or combo box in an HTML form, we don't want
+        # to place the caret inside the list, but rather treat the list
+        # as a single object.  Otherwise, if it has children, look there.
         #
-        elif obj.childCount and obj[0] \
-             and not ((obj.getRole() == pyatspi.ROLE_LIST) \
-                 and obj.getState().contains(pyatspi.STATE_FOCUSABLE)):
+        elif obj.childCount and obj[0] and not doNotDescend:
             try:
                 return self.findNextCaretInOrder(obj[0],
                                                  -1,
@@ -6496,6 +6507,12 @@
         if not obj or not self.inDocumentContent(obj):
             return [None, -1]
 
+        # We do not want to descend objects of certain role types.
+        #
+        doNotDescend = obj.getState().contains(pyatspi.STATE_FOCUSABLE) \
+                       and obj.getRole() in [pyatspi.ROLE_COMBO_BOX,
+                                             pyatspi.ROLE_LIST]
+
         text = self.queryNonEmptyText(obj)
         if text and not (self.isAriaWidget(obj) \
                          and obj.getRole() == pyatspi.ROLE_LIST):
@@ -6526,14 +6543,11 @@
                 else:
                     previousOffset -= 1
 
-        # If this is a list in an HTML form, we don't want to place the
-        # caret inside the list, but rather treat the list as a single
-        # object.  Otherwise, if it has children, look there.
+        # If this is a list or combo box in an HTML form, we don't want
+        # to place the caret inside the list, but rather treat the list
+        # as a single object.  Otherwise, if it has children, look there.
         #
-        elif obj.childCount and obj[obj.childCount - 1] \
-             and not ((obj.getRole() == pyatspi.ROLE_LIST) \
-                 and obj.getState().contains(pyatspi.STATE_FOCUSABLE)):
-
+        elif obj.childCount and obj[obj.childCount - 1]and not doNotDescend:
             try:
                 return self.findPreviousCaretInOrder(
                     obj[obj.childCount - 1],
@@ -7653,8 +7667,9 @@
         character = self.getCharacterAtOffset(obj, characterOffset)
         if character:
             if self.isAriaWidget() \
-                 or not (obj.getRole() == pyatspi.ROLE_LIST_ITEM \
-                 and not obj.getState().contains(pyatspi.STATE_FOCUSABLE)):
+               or useNewLineNav \
+               or not (obj.getRole() == pyatspi.ROLE_LIST_ITEM \
+                     and not obj.getState().contains(pyatspi.STATE_FOCUSABLE)):
                 obj.queryText().setCaretOffset(characterOffset)
                 mag.magnifyAccessible(None,
                                       obj,
@@ -7753,6 +7768,54 @@
         self.updateBraille(obj)
         self.speakContents(self.getWordContentsAtOffset(obj, startOffset))
 
+    def altFindPreviousLine(self, obj, characterOffset):
+        """Locates the caret offset at the previous line in the document
+        window."""
+
+        
+        thisLine = self.altGetLineContents(obj, characterOffset)
+        [lastObj, lastOffset] = self.findPreviousCaretInOrder(thisLine[0][0],
+                                                              thisLine[0][1])
+        if not lastObj:
+            return
+
+        text = self.queryNonEmptyText(lastObj)
+        if text and text.getText(lastOffset, lastOffset + 1) == "\n":
+            [lastObj, lastOffset] = self.findPreviousCaretInOrder(lastObj,
+                                                                  lastOffset)
+
+        extents = self.getExtents(lastObj, lastOffset, lastOffset + 1)
+        prevObj = lastObj
+        offset = lastOffset
+        while prevObj and prevObj.getRole() != pyatspi.ROLE_DOCUMENT_FRAME:
+            [prevObj, offset] = self.findPreviousCaretInOrder(prevObj, offset)
+            text = self.queryNonEmptyText(prevObj)
+            if text:
+                line = text.getTextAtOffset(offset,
+                                            pyatspi.TEXT_BOUNDARY_LINE_START)
+                unicodeText = line[0].decode("UTF-8")
+                if unicodeText.startswith(self.EMBEDDED_OBJECT_CHARACTER):
+                    childIndex = self.getChildIndex(prevObj, line[1])
+                    childText = self.queryNonEmptyText(prevObj[childIndex])
+                    if childText:
+                        prevObj = prevObj[childIndex]
+                        line = \
+                            childText.getTextAtOffset(childText.characterCount,
+                                              pyatspi.TEXT_BOUNDARY_LINE_START)
+                    else:
+                        line = text.getTextAfterOffset(offset,
+                                              pyatspi.TEXT_BOUNDARY_LINE_START)
+                offset = line[1]
+
+            newExtents = self.getExtents(prevObj, offset, offset + 1)
+            if self.onSameLine(extents, newExtents):
+                lastObj = prevObj
+                lastOffset = offset
+            else:
+                break
+
+        return [lastObj, lastOffset]
+
     def findPreviousLine(self, obj, characterOffset):
         """Locates the caret offset at the previous line in the document
         window, attempting to preserve horizontal caret position.
@@ -7765,6 +7828,11 @@
         Returns the [obj, characterOffset] at which to position the caret.
         """
 
+        if useNewLineNav:
+            [myPrevObj, myOffset] = self.altFindPreviousLine(obj,
+                                                             characterOffset)
+            return myPrevObj, myOffset
+
         lineExtents = self.getExtents(
             obj, characterOffset, characterOffset + 1)
         try:
@@ -7859,8 +7927,37 @@
                                               lastCharacterOffset,
                                               lastCharacterOffset + 1)
 
+#        if myPrevObj != lastObj or myOffset != lastCharacterOffset:
+#            print "FPL difference:"
+#            print "mine:", myPrevObj, myOffset
+#            print "orig:", lastObj, lastCharacterOffset
+
         return [lastObj, lastCharacterOffset]
 
+    def altFindNextLine(self, obj, characterOffset):
+        """Locates the caret offset at the next line in the document
+        window."""
+
+        currentLine = self.altGetLineContents(obj, characterOffset)
+        [nextObj, nextOffset] = self.findNextCaretInOrder(currentLine[-1][0],
+                                                          currentLine[-1][2])
+
+        # We need to be sure that we've actually found a new line rather than
+        # a space at the end of the current line.
+        #
+        text = self.queryNonEmptyText(nextObj)
+        if text:
+            line = text.getTextAfterOffset(nextOffset,
+                                           pyatspi.TEXT_BOUNDARY_LINE_START)
+            if not len(line[0].strip()) \
+                   and nextObj.getRole() != pyatspi.ROLE_ENTRY:
+                [nextObj, nextOffset] = \
+                          self.findNextCaretInOrder(nextObj, nextOffset)
+            else:
+                nextOffset = line[1]
+
+        return [nextObj, nextOffset]
+
     def findNextLine(self, obj, characterOffset):
         """Locates the caret offset at the next line in the document
         window, attempting to preserve horizontal caret position.
@@ -7873,6 +7970,10 @@
         Returns the [obj, characterOffset] at which to position the caret.
         """
 
+        if useNewLineNav:
+            [myNextObj, myOffset] = self.altFindNextLine(obj, characterOffset)
+            return myNextObj, myOffset
+
         lineExtents = self.getExtents(
             obj, characterOffset, characterOffset + 1)
         try:
@@ -7944,12 +8045,21 @@
             [obj, characterOffset] = \
                   self.findNextCaretInOrder(obj, characterOffset)
 
+#        if myNextObj != lastObj or myOffset != lastCharacterOffset:
+#            print "FNL difference:"
+#            print "mine:", myNextObj, myOffset
+#            print "orig:", lastObj, lastCharacterOffset
+
         return [lastObj, lastCharacterOffset]
 
     def goPreviousLine(self, inputEvent):
         """Positions the caret offset at the previous line in the document
         window, attempting to preserve horizontal caret position.
         """
+
+        if useNewLineNav:
+            return self.altGoPreviousLine(inputEvent)
+
         [obj, characterOffset] = self.getCaretContext()
         [previousObj, previousCharOffset] = \
                                    self.findPreviousLine(obj, characterOffset)
@@ -7966,6 +8076,10 @@
         """Positions the caret offset at the next line in the document
         window, attempting to preserve horizontal caret position.
         """
+
+        if useNewLineNav:
+            return self.altGoNextLine(inputEvent)
+
         [obj, characterOffset] = self.getCaretContext()
         [nextObj, nextCharOffset] = self.findNextLine(obj, characterOffset)
         self.setCaretPosition(nextObj, nextCharOffset)
@@ -7976,6 +8090,69 @@
         #contents = self.getLineContentsAtOffset(nextObj, nextCharOffset)
         #self.dumpContents(inputEvent, contents)
 
+    def altGoPreviousLine(self, inputEvent):
+        """Positions the caret offset at the previous line in the document
+        window, attempting to preserve horizontal caret position.
+        """
+
+        [obj, offset] = self.getCaretContext()
+        [lastObj, lastOffset] = self.altFindPreviousLine(obj, offset)
+        prevLine = self.getLineContentsAtOffset(lastObj, lastOffset)
+        prevObj = prevLine[0][0]
+        prevOffset = prevLine[0][1]
+
+        if not arrowToLineBeginning:
+            extents = self.getExtents(obj, offset, offset + 1)
+            oldX = extents[0]
+            for item in prevLine:
+                extents = self.getExtents(item[0], item[1], item[2])
+                newX1 = extents[0]
+                newX2 = newX1 + extents[2]
+                if newX1 <= oldX <= newX2:
+                    prevObj = item[0]
+                    prevOffset = 0
+                    text = self.queryNonEmptyText(prevObj)
+                    if text:
+                        newY = extents[1] + extents[3] / 2
+                        prevOffset = text.getOffsetAtPoint(oldX, newY, 0)
+                    break
+
+        self._currentLineContents = prevLine
+        self.setCaretPosition(prevObj, prevOffset)
+        self.presentLine(prevObj, prevOffset)
+
+    def altGoNextLine(self, inputEvent):
+        """Positions the caret offset at the next line in the document
+        window, attempting to preserve horizontal caret position.
+        """
+
+        [obj, offset] = self.getCaretContext()
+        [nextObj, nextOffset] = self.altFindNextLine(obj, offset)
+        if not nextObj:
+            return
+
+        nextLine = self.getLineContentsAtOffset(nextObj, nextOffset)
+
+        if not arrowToLineBeginning:
+            extents = self.getExtents(obj, offset, offset + 1)
+            oldX = extents[0]
+            for item in nextLine:
+                extents = self.getExtents(item[0], item[1], item[2])
+                newX1 = extents[0]
+                newX2 = newX1 + extents[2]
+                if newX1 <= oldX <= newX2:
+                    nextObj = item[0]
+                    nextOffset = 0
+                    text = self.queryNonEmptyText(nextObj)
+                    if text:
+                        newY = extents[1] + extents[3] / 2
+                        nextOffset = text.getOffsetAtPoint(oldX, newY, 0)
+                    break
+
+        self._currentLineContents = nextLine
+        self.setCaretPosition(nextObj, nextOffset)
+        self.presentLine(nextObj, nextOffset)
+
     def expandComboBox(self, inputEvent):
         """If focus is on a menu item, but the containing combo box does not
         have focus, give the combo box focus and expand it.  Note that this
