Index: src/orca/scripts/toolkits/Gecko/script.py
===================================================================
--- src/orca/scripts/toolkits/Gecko/script.py	(revision 4103)
+++ src/orca/scripts/toolkits/Gecko/script.py	(working copy)
@@ -3126,24 +3126,123 @@
         """Determines if we should look any further at the object
         for flat review."""
 
-        # [[[TODO: HACK - WDW Gecko has issues about the SHOWING
-        # state of objects, especially those in document frames.
-        # It tells us the content in tabs that are not showing
-        # is actually showing.  See:
+        # It should be enough to check for STATE_SHOWING, but Gecko seems
+        # to reverse STATE_SHOWING and STATE_VISIBLE, exposing STATE_SHOWING
+        # for objects which are offscreen. So, we'll check for both. See
+        # bug #542833. [[[TODO - JD: We're putting this check in just this
+        # script for now to be on the safe side. Consider for the default
+        # script as well?]]]
         #
-        # http://bugzilla.gnome.org/show_bug.cgi?id=408071
+        try:
+            state = obj.getState()
+        except:
+            debug.printException(debug.LEVEL_WARNING)
+            return False
+        else:
+            return state.contains(pyatspi.STATE_SHOWING) \
+                   and state.contains(pyatspi.STATE_VISIBLE)
+ 
+    def getShowingDescendants(self, parent):
+        """Given an accessible object, returns a list of accessible children
+        that are actually showing/visible/pursable for flat review. We're
+        overriding the default method here primarily to handle enormous
+        tree tables (such as the Thunderbird message list) which do not
+        manage their descendants.
+
+        Arguments:
+        - parent: The accessible which manages its descendants
+
+        Returns a list of Accessible descendants which are showing.
+        """
+
+        if not parent:
+            return []
+
+        # If this object is not a tree table, if it manages its descendants,
+        # or if it doesn't have very many children, let the default script
+        # handle it.
         #
-        # To work around this, we do a little extra check.  If
-        # the obj is a document, and it's not the one that
-        # Firefox is currently showing the user, we skip it.
+        if parent.getRole() != pyatspi.ROLE_TREE_TABLE \
+           or parent.getState().contains(pyatspi.STATE_MANAGES_DESCENDANTS) \
+           or parent.childCount <= 50:
+            return default.Script.getShowingDescendants(self, parent)
+
+        try:
+            table = parent.queryTable()
+        except NotImplementedError:
+            return []
+
+        descendants = []
+
+        # First figure out what columns are visible as there's no point
+        # in examining cells which we know won't be visible.
+        # 
+        visibleColumns = []
+        for i in range(table.nColumns):
+            header = table.getColumnHeader(i)
+            if self.pursueForFlatReview(header):
+                visibleColumns.append(i)
+                descendants.append(header)
+
+        if not len(visibleColumns):
+            return []
+
+        # Now that we know in which columns we can expect to find visible
+        # cells, try to quickly locate a visible row.
         #
-        pursue = default.Script.pursueForFlatReview(self, obj)
-        if pursue and (obj.getRole() == pyatspi.ROLE_DOCUMENT_FRAME):
-            documentFrame = self.getDocumentFrame()
-            pursue = obj == documentFrame
+        startingRow = 0
 
-        return pursue
+        # If we have one or more selected items, odds are fairly good
+        # (although not guaranteed) that one of those items happens to
+        # be showing. Failing that, calculate how many rows can fit in
+        # the exposed portion of the tree table and scroll down.
+        #
+        selectedRows = table.getSelectedRows()
+        for row in selectedRows:
+            acc = table.getAccessibleAt(row, visibleColumns[0])
+            if self.pursueForFlatReview(acc):
+                startingRow = row
+                break
+        else:
+            try:
+                tableExtents = parent.queryComponent().getExtents(0)
+                acc = table.getAccessibleAt(0, visibleColumns[0])
+                cellExtents = acc.queryComponent().getExtents(0)
+            except:
+                pass
+            else:
+                rowIncrement = max(1, tableExtents.height / cellExtents.height)
+                for row in range(0, table.nRows, rowIncrement):
+                    acc = table.getAccessibleAt(row, visibleColumns[0])
+                    if acc and self.pursueForFlatReview(acc):
+                        startingRow = row
+                        break
 
+        # Get everything after this point which is visible.
+        #
+        for row in range(startingRow, table.nRows):
+            acc = table.getAccessibleAt(row, visibleColumns[0])
+            if self.pursueForFlatReview(acc):
+                descendants.append(acc)
+                for col in visibleColumns[1:len(visibleColumns)]:
+                    descendants.append(table.getAccessibleAt(row, col))
+            else:
+                break
+
+        # Get everything before this point which is visible.
+        #
+        for row in range(startingRow - 1, -1, -1):
+            acc = table.getAccessibleAt(row, visibleColumns[0])
+            if self.pursueForFlatReview(acc):
+                thisRow = [acc]
+                for col in visibleColumns[1:len(visibleColumns)]:
+                    thisRow.append(table.getAccessibleAt(row, col))
+                descendants[0:0] = thisRow
+            else:
+                break
+
+        return descendants
+
     def getHeadingLevel(self, obj):
         """Determines the heading level of the given object.  A value
         of 0 means there is no heading level."""
Index: src/orca/flat_review.py
===================================================================
--- src/orca/flat_review.py	(revision 4103)
+++ src/orca/flat_review.py	(working copy)
@@ -26,7 +26,6 @@
 __license__   = "LGPL"
 
 import re
-import sys
 
 import pyatspi
 import braille
@@ -597,11 +596,6 @@
     WRAP_TOP_BOTTOM = 1 << 1
     WRAP_ALL        = (WRAP_LINE | WRAP_TOP_BOTTOM)
 
-    # A minimal chunk to jump around should we not really know where we
-    # are going.
-    #
-    GRID_SIZE = 7
-
     def __init__(self, script):
         """Create a new Context that will be used for handling flat
         review mode.
@@ -730,34 +724,6 @@
         #
         self.targetCharInfo = None
 
-
-    def visible(self,
-                ax, ay, awidth, aheight,
-                bx, by, bwidth, bheight):
-        """Returns true if any portion of region 'a' is in region 'b'
-        """
-        highestBottom = min(ay + aheight, by + bheight)
-        lowestTop = max(ay, by)
-
-        leftMostRightEdge = min(ax + awidth, bx + bwidth)
-        rightMostLeftEdge = max(ax, bx)
-
-        visible = False
-
-        if (lowestTop <= highestBottom) \
-           and (rightMostLeftEdge <= leftMostRightEdge):
-            visible = True
-        elif (aheight == 0):
-            if (awidth == 0):
-                visible = (lowestTop == highestBottom) \
-                          and (leftMostRightEdge == rightMostLeftEdge)
-            else:
-                visible = leftMostRightEdge <= rightMostLeftEdge
-        elif (awidth == 0):
-            visible = (lowestTop <= highestBottom)
-
-        return visible
-
     def clip(self,
              ax, ay, awidth, aheight,
              bx, by, bwidth, bheight):
@@ -819,9 +785,9 @@
             else:
                 [x, y, width, height] = text.getRangeExtents( \
                           substringStartOffset, substringEndOffset, 0)
-                if self.visible(x, y, width, height,
-                                cliprect.x, cliprect.y,
-                                cliprect.width, cliprect.height):
+                if self.script.visible(x, y, width, height,
+                                       cliprect.x, cliprect.y,
+                                       cliprect.width, cliprect.height):
 
                     anyVisible = True
 
@@ -1094,10 +1060,10 @@
         #
         extents = icomponent.getExtents(0)
 
-        if not self.visible(extents.x, extents.y,
-                            extents.width, extents.height,
-                            cliprect.x, cliprect.y,
-                            cliprect.width, cliprect.height):
+        if not self.script.visible(extents.x, extents.y,
+                                   extents.width, extents.height,
+                                   cliprect.x, cliprect.y,
+                                   cliprect.width, cliprect.height):
             return []
 
         debug.println(
@@ -1143,9 +1109,9 @@
             [width, height] = iimage.getImageSize()
 
             if (width != 0) and (height != 0) \
-                   and self.visible(x, y, width, height,
-                                    cliprect.x, cliprect.y,
-                                    cliprect.width, cliprect.height):
+                   and self.script.visible(x, y, width, height,
+                                           cliprect.x, cliprect.y,
+                                           cliprect.width, cliprect.height):
 
                 clipping = self.clip(x, y, width, height,
                                      cliprect.x, cliprect.y,
@@ -1216,91 +1182,6 @@
 
         return zones
 
-    def getShowingDescendants(self, parent):
-        """Given a parent that manages its descendants, return a list of
-        Accessible children that are actually showing.  This algorithm
-        was inspired a little by the srw_elements_from_accessible logic
-        in Gnopernicus, and makes the assumption that the children of
-        an object that manages its descendants are arranged in a row
-        and column format.
-        """
-
-        if not parent:
-            return []
-
-        try:
-            icomponent = parent.queryComponent()
-        except NotImplementedError:
-            return []
-
-        descendants = []
-
-        parentExtents = icomponent.getExtents(0)
-
-        # [[[TODO: WDW - HACK related to GAIL bug where table column
-        # headers seem to be ignored:
-        # http://bugzilla.gnome.org/show_bug.cgi?id=325809.  The
-        # problem is that this causes getAccessibleAtPoint to return
-        # the cell effectively below the real cell at a given point,
-        # making a mess of everything.  So...we just manually add in
-        # showing headers for now.  The remainder of the logic below
-        # accidentally accounts for this offset, yet it should also
-        # work when bug 325809 is fixed.]]]
-        #
-        try:
-            table = parent.queryTable()
-        except NotImplementedError:
-            table = None
-            
-        if table:
-            for i in range(0, table.nColumns):
-                header = table.getColumnHeader(i)
-                if header:
-                    extents = header.queryComponent().getExtents(0)
-                    stateset = header.getState()
-                    if stateset.contains(pyatspi.STATE_SHOWING) \
-                       and (extents.x >= 0) and (extents.y >= 0) \
-                       and (extents.width > 0) and (extents.height > 0) \
-                       and self.visible(extents.x, extents.y,
-                                        extents.width, extents.height,
-                                        parentExtents.x, parentExtents.y,
-                                        parentExtents.width,
-                                        parentExtents.height):
-                        descendants.append(header)
-
-        # This algorithm goes left to right, top to bottom while attempting
-        # to do *some* optimization over queries.  It could definitely be
-        # improved.
-        #
-        currentY = parentExtents.y
-        while currentY < (parentExtents.y + parentExtents.height):
-            currentX = parentExtents.x
-            minHeight = sys.maxint
-            while currentX < (parentExtents.x + parentExtents.width):
-                child = icomponent.getAccessibleAtPoint(currentX,
-                                                            currentY,
-                                                            0)
-                if child:
-                    extents = child.queryComponent().getExtents(0)
-                    if extents.x >= 0 and extents.y >= 0:
-                        newX = extents.x + extents.width
-                        minHeight = min(minHeight, extents.height)
-                        if not descendants.count(child):
-                            descendants.append(child)
-                    else:
-                        newX = currentX + self.GRID_SIZE
-                else:
-                    newX = currentX + self.GRID_SIZE
-                if newX <= currentX:
-                    currentX += self.GRID_SIZE
-                else:
-                    currentX = newX
-            if minHeight == sys.maxint:
-                minHeight = self.GRID_SIZE
-            currentY += minHeight
-
-        return descendants
-
     def getShowingZones(self, root):
         """Returns a list of all interesting, non-intersecting, regions
         that are drawn on the screen.  Each element of the list is the
@@ -1383,11 +1264,11 @@
                 zones = self.getZonesFromAccessible(root, rootexts)
         except NotImplementedError:
             pass
-        
-        stateset = root.getState()
-        if stateset.contains(pyatspi.STATE_MANAGES_DESCENDANTS) \
-           and (root.childCount > 50):
-            for child in self.getShowingDescendants(root):
+
+        showingDescendants = \
+            self.script.getShowingDescendants(root)
+        if len(showingDescendants):
+            for child in showingDescendants:
                 zones.extend(self.getShowingZones(child))
         else:
             for i in range(0, root.childCount):
Index: src/orca/default.py
===================================================================
--- src/orca/default.py	(revision 4103)
+++ src/orca/default.py	(working copy)
@@ -40,6 +40,7 @@
 
 import locale
 import math
+import sys
 import time
 
 import pyatspi
@@ -4517,8 +4518,136 @@
     def pursueForFlatReview(self, obj):
         """Determines if we should look any further at the object
         for flat review."""
-        return obj.getState().contains(pyatspi.STATE_SHOWING)
 
+        try:
+            state = obj.getState()
+        except:
+            debug.printException(debug.LEVEL_WARNING)
+            return False
+        else:
+            return state.contains(pyatspi.STATE_SHOWING)
+
+    def getShowingDescendants(self, parent):
+        """Given a parent that manages its descendants, return a list of
+        Accessible children that are actually showing.  This algorithm
+        was inspired a little by the srw_elements_from_accessible logic
+        in Gnopernicus, and makes the assumption that the children of
+        an object that manages its descendants are arranged in a row
+        and column format.
+
+        Arguments:
+        - parent: The accessible which manages its descendants
+
+        Returns a list of Accessible descendants which are showing.
+        """
+
+        if not parent:
+            return []
+
+        if not parent.getState().contains(pyatspi.STATE_MANAGES_DESCENDANTS) \
+           or parent.childCount <= 50:
+            return []
+
+        try:
+            icomponent = parent.queryComponent()
+        except NotImplementedError:
+            return []
+
+        descendants = []
+
+        parentExtents = icomponent.getExtents(0)
+
+        # [[[TODO: WDW - HACK related to GAIL bug where table column
+        # headers seem to be ignored:
+        # http://bugzilla.gnome.org/show_bug.cgi?id=325809.  The
+        # problem is that this causes getAccessibleAtPoint to return
+        # the cell effectively below the real cell at a given point,
+        # making a mess of everything.  So...we just manually add in
+        # showing headers for now.  The remainder of the logic below
+        # accidentally accounts for this offset, yet it should also
+        # work when bug 325809 is fixed.]]]
+        #
+        try:
+            table = parent.queryTable()
+        except NotImplementedError:
+            table = None
+            
+        if table:
+            for i in range(0, table.nColumns):
+                header = table.getColumnHeader(i)
+                if header:
+                    extents = header.queryComponent().getExtents(0)
+                    stateset = header.getState()
+                    if stateset.contains(pyatspi.STATE_SHOWING) \
+                       and (extents.x >= 0) and (extents.y >= 0) \
+                       and (extents.width > 0) and (extents.height > 0) \
+                       and self.visible(extents.x, extents.y,
+                                        extents.width, extents.height,
+                                        parentExtents.x, parentExtents.y,
+                                        parentExtents.width,
+                                        parentExtents.height):
+                        descendants.append(header)
+
+        # This algorithm goes left to right, top to bottom while attempting
+        # to do *some* optimization over queries.  It could definitely be
+        # improved. The gridSize is a minimal chunk to jump around in the
+        # table.
+        #
+        gridSize = 7
+        currentY = parentExtents.y
+        while currentY < (parentExtents.y + parentExtents.height):
+            currentX = parentExtents.x
+            minHeight = sys.maxint
+            while currentX < (parentExtents.x + parentExtents.width):
+                child = icomponent.getAccessibleAtPoint(currentX, currentY, 0)
+                if child:
+                    extents = child.queryComponent().getExtents(0)
+                    if extents.x >= 0 and extents.y >= 0:
+                        newX = extents.x + extents.width
+                        minHeight = min(minHeight, extents.height)
+                        if not descendants.count(child):
+                            descendants.append(child)
+                    else:
+                        newX = currentX + gridSize
+                else:
+                    newX = currentX + gridSize
+                if newX <= currentX:
+                    currentX += gridSize
+                else:
+                    currentX = newX
+            if minHeight == sys.maxint:
+                minHeight = gridSize
+            currentY += minHeight
+
+        return descendants
+
+    def visible(self,
+                ax, ay, awidth, aheight,
+                bx, by, bwidth, bheight):
+        """Returns true if any portion of region 'a' is in region 'b'
+        """
+        highestBottom = min(ay + aheight, by + bheight)
+        lowestTop = max(ay, by)
+
+        leftMostRightEdge = min(ax + awidth, bx + bwidth)
+        rightMostLeftEdge = max(ax, bx)
+
+        visible = False
+
+        if (lowestTop <= highestBottom) \
+           and (rightMostLeftEdge <= leftMostRightEdge):
+            visible = True
+        elif (aheight == 0):
+            if (awidth == 0):
+                visible = (lowestTop == highestBottom) \
+                          and (leftMostRightEdge == rightMostLeftEdge)
+            else:
+                visible = leftMostRightEdge <= rightMostLeftEdge
+        elif (awidth == 0):
+            visible = (lowestTop <= highestBottom)
+
+        return visible
+
     def getFlatReviewContext(self):
         """Returns the flat review context, creating one if necessary."""
 
