Bug 1460244 - Tables with CSS display properties no longer participate in layout table calculation, r=marcoz
authorAlexander Surkov <surkov.alexander@gmail.com>
Fri, 25 May 2018 10:55:52 -0400
changeset 419895 50a6c79860000396a9d1378687e150310ae96eb4
parent 419894 ea19ea9820f496f682c71634a011991c28f6ab5d
child 419896 94d7f0e1c4d0390450028972cfeb65e0550b9892
child 419952 b11b8740599335d6e55806b0339be41b35046e62
push id34052
push userccoroiu@mozilla.com
push dateFri, 25 May 2018 17:52:14 +0000
treeherdermozilla-central@94d7f0e1c4d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz
bugs1460244
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1460244 - Tables with CSS display properties no longer participate in layout table calculation, r=marcoz
accessible/generic/ARIAGridAccessible.cpp
accessible/generic/ARIAGridAccessible.h
accessible/generic/TableAccessible.cpp
accessible/generic/TableAccessible.h
accessible/generic/moz.build
accessible/html/HTMLTableAccessible.cpp
accessible/html/HTMLTableAccessible.h
accessible/tests/mochitest/table/test_layoutguess.html
--- a/accessible/generic/ARIAGridAccessible.cpp
+++ b/accessible/generic/ARIAGridAccessible.cpp
@@ -35,16 +35,31 @@ ARIAGridAccessible::
 
 role
 ARIAGridAccessible::NativeRole() const
 {
   a11y::role r = GetAccService()->MarkupRole(mContent);
   return r != roles::NOTHING ? r : roles::TABLE;
 }
 
+already_AddRefed<nsIPersistentProperties>
+ARIAGridAccessible::NativeAttributes()
+{
+  nsCOMPtr<nsIPersistentProperties> attributes =
+    AccessibleWrap::NativeAttributes();
+
+  if (IsProbablyLayoutTable()) {
+    nsAutoString unused;
+    attributes->SetStringProperty(NS_LITERAL_CSTRING("layout-guess"),
+                                  NS_LITERAL_STRING("true"), unused);
+  }
+
+  return attributes.forget();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Table
 
 uint32_t
 ARIAGridAccessible::ColCount() const
 {
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = rowIter.Next();
--- a/accessible/generic/ARIAGridAccessible.h
+++ b/accessible/generic/ARIAGridAccessible.h
@@ -21,16 +21,17 @@ class ARIAGridAccessible : public Access
 {
 public:
   ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_INLINE_DECL_REFCOUNTING_INHERITED(ARIAGridAccessible, AccessibleWrap)
 
   // Accessible
   virtual a11y::role NativeRole() const override;
+  virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
   virtual TableAccessible* AsTable() override { return this; }
 
   // TableAccessible
   virtual uint32_t ColCount() const override;
   virtual uint32_t RowCount() override;
   virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override;
   virtual bool IsColSelected(uint32_t aColIdx) override;
   virtual bool IsRowSelected(uint32_t aRowIdx) override;
new file mode 100644
--- /dev/null
+++ b/accessible/generic/TableAccessible.cpp
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TableAccessible.h"
+
+#include "Accessible-inl.h"
+
+#include "nsTableCellFrame.h"
+#include "nsTableWrapperFrame.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+bool
+TableAccessible::IsProbablyLayoutTable()
+{
+  // Implement a heuristic to determine if table is most likely used for layout.
+
+  // XXX do we want to look for rowspan or colspan, especialy that span all but
+  // a couple cells  at the beginning or end of a row/col, and especially when
+  // they occur at the edge of a table?
+
+  // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
+  // This will allow release trunk builds to be used by testers to refine
+  // the algorithm. Integrate it into Logging.
+  // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
+#ifdef SHOW_LAYOUT_HEURISTIC
+#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
+  { \
+    mLayoutHeuristic = isLayout ? \
+      NS_LITERAL_STRING("layout table: " heuristic) : \
+      NS_LITERAL_STRING("data table: " heuristic); \
+    return isLayout; \
+  }
+#else
+#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; }
+#endif
+
+  Accessible* thisacc = AsAccessible();
+
+  // Need to see all elements while document is being edited.
+  if (thisacc->Document()->State() & states::EDITABLE) {
+    RETURN_LAYOUT_ANSWER(false, "In editable document");
+  }
+
+  // Check to see if an ARIA role overrides the role from native markup,
+  // but for which we still expose table semantics (treegrid, for example).
+  if (thisacc->HasARIARole()) {
+    RETURN_LAYOUT_ANSWER(false, "Has role attribute");
+  }
+
+  dom::Element* el = thisacc->Elm();
+  if (el->IsMathMLElement(nsGkAtoms::mtable_)) {
+    RETURN_LAYOUT_ANSWER(false, "MathML matrix");
+  }
+
+  MOZ_ASSERT(el->IsHTMLElement(nsGkAtoms::table),
+             "Table should not be built by CSS display:table style");
+
+  // Check if datatable attribute has "0" value.
+  if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable,
+                      NS_LITERAL_STRING("0"), eCaseMatters)) {
+    RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
+  }
+
+  // Check for legitimate data table attributes.
+  nsAutoString summary;
+  if (el->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
+      !summary.IsEmpty()) {
+    RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
+  }
+
+  // Check for legitimate data table elements.
+  Accessible* caption = thisacc->FirstChild();
+  if (caption && caption->IsHTMLCaption() && caption->HasChildren()) {
+    RETURN_LAYOUT_ANSWER(false, "Not empty caption -- legitimate table structures");
+  }
+
+  for (nsIContent* childElm = el->GetFirstChild(); childElm;
+       childElm = childElm->GetNextSibling()) {
+    if (!childElm->IsHTMLElement())
+      continue;
+
+    if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col,
+                                      nsGkAtoms::colgroup,
+                                      nsGkAtoms::tfoot,
+                                      nsGkAtoms::thead)) {
+      RETURN_LAYOUT_ANSWER(false,
+                           "Has col, colgroup, tfoot or thead -- legitimate table structures");
+    }
+
+    if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
+      for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
+           rowElm = rowElm->GetNextSibling()) {
+        if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
+          for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
+               cellElm = cellElm->GetNextSibling()) {
+            if (cellElm->IsHTMLElement()) {
+
+              if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
+                RETURN_LAYOUT_ANSWER(false,
+                                     "Has th -- legitimate table structures");
+              }
+
+              if (cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::headers) ||
+                  cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope) ||
+                  cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::abbr)) {
+                RETURN_LAYOUT_ANSWER(false,
+                                     "Has headers, scope, or abbr attribute -- legitimate table structures");
+              }
+
+              Accessible* cell = thisacc->Document()->GetAccessible(cellElm);
+              if (cell && cell->ChildCount() == 1 &&
+                  cell->FirstChild()->IsAbbreviation()) {
+                RETURN_LAYOUT_ANSWER(false,
+                                     "has abbr -- legitimate table structures");
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Check for nested tables.
+  nsCOMPtr<nsIHTMLCollection> nestedTables =
+    el->GetElementsByTagName(NS_LITERAL_STRING("table"));
+  if (nestedTables->Length() > 0) {
+    RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
+  }
+
+  // If only 1 column or only 1 row, it's for layout.
+  auto colCount = ColCount();
+  if (colCount <= 1) {
+    RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
+  }
+  auto rowCount = RowCount();
+  if (rowCount <=1) {
+    RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
+  }
+
+  // Check for many columns.
+  if (colCount >= 5) {
+    RETURN_LAYOUT_ANSWER(false, ">=5 columns");
+  }
+
+  // Now we know there are 2-4 columns and 2 or more rows. Check to see if
+  // there are visible borders on the cells.
+  // XXX currently, we just check the first cell -- do we really need to do more?
+  nsTableWrapperFrame* tableFrame = do_QueryFrame(el->GetPrimaryFrame());
+  if (!tableFrame) {
+    RETURN_LAYOUT_ANSWER(false, "table with no frame!");
+  }
+
+  nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
+  if (!cellFrame) {
+    RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
+  }
+
+  nsMargin border;
+  cellFrame->GetXULBorder(border);
+  if (border.top && border.bottom && border.left && border.right) {
+    RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
+  }
+
+  // Rules for non-bordered tables with 2-4 columns and 2+ rows from here on
+  // forward.
+
+  // Check for styled background color across rows (alternating background
+  // color is a common feature for data tables).
+  auto childCount = thisacc->ChildCount();
+  nscolor rowColor = 0;
+  nscolor prevRowColor;
+  for (auto childIdx = 0U; childIdx < childCount; childIdx++) {
+    Accessible* child = thisacc->GetChildAt(childIdx);
+    if (child->IsHTMLTableRow()) {
+      prevRowColor = rowColor;
+      nsIFrame* rowFrame = child->GetFrame();
+      MOZ_ASSERT(rowFrame, "Table hierarchy got screwed up");
+      if (!rowFrame) {
+        RETURN_LAYOUT_ANSWER(false, "Unexpected table hierarchy");
+      }
+
+      rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
+
+      if (childIdx > 0 && prevRowColor != rowColor) {
+        RETURN_LAYOUT_ANSWER(
+          false, "2 styles of row background color, non-bordered"
+        );
+      }
+    }
+  }
+
+  // Check for many rows.
+  const uint32_t kMaxLayoutRows = 20;
+  if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
+    RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
+  }
+
+  // Check for very wide table.
+  nsIFrame* documentFrame = thisacc->Document()->GetFrame();
+  nsSize documentSize = documentFrame->GetSize();
+  if (documentSize.width > 0) {
+    nsSize tableSize = thisacc->GetFrame()->GetSize();
+    int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
+    if (percentageOfDocWidth > 95) {
+      // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
+      // Probably for layout
+      RETURN_LAYOUT_ANSWER(
+        true, "<= 4 columns, table width is 95% of document width"
+      );
+    }
+  }
+
+  // Two column rules.
+  if (rowCount * colCount <= 10) {
+    RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
+  }
+
+  static const nsLiteralString tags[] = {
+    NS_LITERAL_STRING("embed"),
+    NS_LITERAL_STRING("object"),
+    NS_LITERAL_STRING("iframe")
+  };
+  for (auto& tag : tags) {
+    nsCOMPtr<nsIHTMLCollection> descendants = el->GetElementsByTagName(tag);
+    if (descendants->Length() > 0) {
+      RETURN_LAYOUT_ANSWER(
+        true, "Has no borders, and has iframe, object or embed, typical of advertisements"
+      );
+    }
+  }
+
+  RETURN_LAYOUT_ANSWER(
+    false, "No layout factor strong enough, so will guess data"
+  );
+}
--- a/accessible/generic/TableAccessible.h
+++ b/accessible/generic/TableAccessible.h
@@ -168,17 +168,17 @@ public:
   /**
    * Unselect the given row leaving other selected rows selected.
    */
   virtual void UnselectRow(uint32_t aRowIdx) {}
 
   /**
    * Return true if the table is probably for layout.
    */
-  virtual bool IsProbablyLayoutTable() { return false; }
+  virtual bool IsProbablyLayoutTable();
 
   /**
    * Convert the table to an Accessible*.
    */
   virtual Accessible* AsAccessible() = 0;
 };
 
 } // namespace a11y
--- a/accessible/generic/moz.build
+++ b/accessible/generic/moz.build
@@ -16,16 +16,17 @@ UNIFIED_SOURCES += [
     'ARIAGridAccessible.cpp',
     'BaseAccessibles.cpp',
     'DocAccessible.cpp',
     'FormControlAccessible.cpp',
     'HyperTextAccessible.cpp',
     'ImageAccessible.cpp',
     'OuterDocAccessible.cpp',
     'RootAccessible.cpp',
+    'TableAccessible.cpp',
     'TableCellAccessible.cpp',
     'TextLeafAccessible.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/html',
     '/accessible/xpcom',
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -855,254 +855,16 @@ HTMLTableAccessible::Description(nsStrin
   if (aDescription.IsEmpty()) {
     bool isProbablyForLayout = IsProbablyLayoutTable();
     aDescription = mLayoutHeuristic;
   }
   printf("\nTABLE: %s\n", NS_ConvertUTF16toUTF8(mLayoutHeuristic).get());
 #endif
 }
 
-bool
-HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty)
-{
-  nsCOMPtr<nsIHTMLCollection> elements =
-    mContent->AsElement()->GetElementsByTagName(aTagName);
-
-  Element* foundItem = elements->Item(0);
-  if (!foundItem)
-    return false;
-
-  if (aAllowEmpty)
-    return true;
-
-  // Make sure that the item we found has contents and either has multiple
-  // children or the found item is not a whitespace-only text node.
-  if (foundItem->GetChildCount() > 1)
-    return true; // Treat multiple child nodes as non-empty
-
-  nsIContent *innerItemContent = foundItem->GetFirstChild();
-  if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
-    return true;
-
-  // If we found more than one node then return true not depending on
-  // aAllowEmpty flag.
-  // XXX it might be dummy but bug 501375 where we changed this addresses
-  // performance problems only. Note, currently 'aAllowEmpty' flag is used for
-  // caption element only. On another hand we create accessible object for
-  // the first entry of caption element (see
-  // HTMLTableAccessible::InsertChildAt).
-  return !!elements->Item(1);
-}
-
-bool
-HTMLTableAccessible::IsProbablyLayoutTable()
-{
-  // Implement a heuristic to determine if table is most likely used for layout
-  // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells
-  // at the beginning or end of a row/col, and especially when they occur at the edge of a table?
-  // XXX expose this info via object attributes to AT-SPI
-
-  // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
-  // This will allow release trunk builds to be used by testers to refine the algorithm
-  // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
-#ifdef SHOW_LAYOUT_HEURISTIC
-#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
-  { \
-    mLayoutHeuristic = isLayout ? \
-      NS_LITERAL_STRING("layout table: " heuristic) : \
-      NS_LITERAL_STRING("data table: " heuristic); \
-    return isLayout; \
-  }
-#else
-#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; }
-#endif
-
-  DocAccessible* docAccessible = Document();
-  if (docAccessible) {
-    uint64_t docState = docAccessible->State();
-    if (docState & states::EDITABLE) {  // Need to see all elements while document is being edited
-      RETURN_LAYOUT_ANSWER(false, "In editable document");
-    }
-  }
-
-  // Check to see if an ARIA role overrides the role from native markup,
-  // but for which we still expose table semantics (treegrid, for example).
-  if (Role() != roles::TABLE)
-    RETURN_LAYOUT_ANSWER(false, "Has role attribute");
-
-  if (mContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
-    // Role attribute is present, but overridden roles have already been dealt with.
-    // Only landmarks and other roles that don't override the role from native
-    // markup are left to deal with here.
-    RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
-  }
-
-  NS_ASSERTION(mContent->IsHTMLElement(nsGkAtoms::table),
-    "table should not be built by CSS display:table style");
-
-  // Check if datatable attribute has "0" value.
-  if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable,
-                            NS_LITERAL_STRING("0"), eCaseMatters)) {
-    RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
-  }
-
-  // Check for legitimate data table attributes.
-  nsAutoString summary;
-  if (mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
-      !summary.IsEmpty())
-    RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
-
-  // Check for legitimate data table elements.
-  Accessible* caption = FirstChild();
-  if (caption && caption->Role() == roles::CAPTION && caption->HasChildren())
-    RETURN_LAYOUT_ANSWER(false, "Not empty caption -- legitimate table structures");
-
-  for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
-       childElm = childElm->GetNextSibling()) {
-    if (!childElm->IsHTMLElement())
-      continue;
-
-    if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col,
-                                      nsGkAtoms::colgroup,
-                                      nsGkAtoms::tfoot,
-                                      nsGkAtoms::thead)) {
-      RETURN_LAYOUT_ANSWER(false,
-                           "Has col, colgroup, tfoot or thead -- legitimate table structures");
-    }
-
-    if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
-      for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
-           rowElm = rowElm->GetNextSibling()) {
-        if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
-          for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
-               cellElm = cellElm->GetNextSibling()) {
-            if (cellElm->IsHTMLElement()) {
-
-              if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
-                RETURN_LAYOUT_ANSWER(false,
-                                     "Has th -- legitimate table structures");
-              }
-
-              if (cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::headers) ||
-                  cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope) ||
-                  cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::abbr)) {
-                RETURN_LAYOUT_ANSWER(false,
-                                     "Has headers, scope, or abbr attribute -- legitimate table structures");
-              }
-
-              Accessible* cell = mDoc->GetAccessible(cellElm);
-              if (cell && cell->ChildCount() == 1 &&
-                  cell->FirstChild()->IsAbbreviation()) {
-                RETURN_LAYOUT_ANSWER(false,
-                                     "has abbr -- legitimate table structures");
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  if (HasDescendant(NS_LITERAL_STRING("table"))) {
-    RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
-  }
-
-  // If only 1 column or only 1 row, it's for layout
-  uint32_t colCount = ColCount();
-  if (colCount <=1) {
-    RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
-  }
-  uint32_t rowCount = RowCount();
-  if (rowCount <=1) {
-    RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
-  }
-
-  // Check for many columns
-  if (colCount >= 5) {
-    RETURN_LAYOUT_ANSWER(false, ">=5 columns");
-  }
-
-  // Now we know there are 2-4 columns and 2 or more rows
-  // Check to see if there are visible borders on the cells
-  // XXX currently, we just check the first cell -- do we really need to do more?
-  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
-  if (!tableFrame)
-    RETURN_LAYOUT_ANSWER(false, "table with no frame!");
-
-  nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
-  if (!cellFrame)
-    RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
-
-  nsMargin border;
-  cellFrame->GetXULBorder(border);
-  if (border.top && border.bottom && border.left && border.right) {
-    RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
-  }
-
-  /**
-   * Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward
-   */
-
-  // Check for styled background color across rows (alternating background
-  // color is a common feature for data tables).
-  uint32_t childCount = ChildCount();
-  nscolor rowColor = 0;
-  nscolor prevRowColor;
-  for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
-    Accessible* child = GetChildAt(childIdx);
-    if (child->Role() == roles::ROW) {
-      prevRowColor = rowColor;
-      nsIFrame* rowFrame = child->GetFrame();
-      MOZ_ASSERT(rowFrame, "Table hierarchy got screwed up");
-      if (!rowFrame) {
-        RETURN_LAYOUT_ANSWER(false, "Unexpected table hierarchy");
-      }
-
-      rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
-
-      if (childIdx > 0 && prevRowColor != rowColor)
-        RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
-    }
-  }
-
-  // Check for many rows
-  const uint32_t kMaxLayoutRows = 20;
-  if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
-    RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
-  }
-
-  // Check for very wide table.
-  nsIFrame* documentFrame = Document()->GetFrame();
-  nsSize documentSize = documentFrame->GetSize();
-  if (documentSize.width > 0) {
-    nsSize tableSize = GetFrame()->GetSize();
-    int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
-    if (percentageOfDocWidth > 95) {
-      // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
-      // Probably for layout
-      RETURN_LAYOUT_ANSWER(true,
-                           "<= 4 columns, table width is 95% of document width");
-    }
-  }
-
-  // Two column rules
-  if (rowCount * colCount <= 10) {
-    RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
-  }
-
-  if (HasDescendant(NS_LITERAL_STRING("embed")) ||
-      HasDescendant(NS_LITERAL_STRING("object")) ||
-      HasDescendant(NS_LITERAL_STRING("iframe"))) {
-    RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, or iframe, typical of advertisements");
-  }
-
-  RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data");
-}
-
-
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLCaptionAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 Relation
 HTMLCaptionAccessible::RelationByType(RelationType aType) const
 {
   Relation rel = HyperTextAccessible::RelationByType(aType);
--- a/accessible/html/HTMLTableAccessible.h
+++ b/accessible/html/HTMLTableAccessible.h
@@ -151,17 +151,16 @@ public:
   virtual void SelectedCells(nsTArray<Accessible*>* aCells) override;
   virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override;
   virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override;
   virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override;
   virtual void SelectCol(uint32_t aColIdx) override;
   virtual void SelectRow(uint32_t aRowIdx) override;
   virtual void UnselectCol(uint32_t aColIdx) override;
   virtual void UnselectRow(uint32_t aRowIdx) override;
-  virtual bool IsProbablyLayoutTable() override;
   virtual Accessible* AsAccessible() override { return this; }
 
   // Accessible
   virtual TableAccessible* AsTable() override { return this; }
   virtual void Description(nsString& aDescription) override;
   virtual a11y::role NativeRole() const override;
   virtual uint64_t NativeState() const override;
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
@@ -194,25 +193,16 @@ protected:
    * @param  aIsOuter  [in] indicates whether all rows or column excepting
    *                    the given one should be unselected or the given one
    *                    should be unselected only
    */
   nsresult RemoveRowsOrColumnsFromSelection(int32_t aIndex,
                                             TableSelection aTarget,
                                             bool aIsOuter);
 
-  /**
-   * Return true if table has an element with the given tag name.
-   *
-   * @param  aTagName     [in] tag name of searched element
-   * @param  aAllowEmpty  [in, optional] points if found element can be empty
-   *                       or contain whitespace text only.
-   */
-  bool HasDescendant(const nsAString& aTagName, bool aAllowEmpty = true);
-
 #ifdef SHOW_LAYOUT_HEURISTIC
   nsString mLayoutHeuristic;
 #endif
 };
 
 /**
  * HTML caption accessible (html:caption).
  */
--- a/accessible/tests/mochitest/table/test_layoutguess.html
+++ b/accessible/tests/mochitest/table/test_layoutguess.html
@@ -9,116 +9,124 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../attributes.js"></script>
 
   <script type="application/javascript">
+    function isLayoutTable(id) {
+      testAttrs(id, { "layout-guess": "true" }, true);
+    }
+    function isDataTable(id) {
+      testAbsentAttrs(id, { "layout-guess": "true" });
+    }
+
     function doTest() {
-      // Attribute we're looking for
-      var attr = {
-        "layout-guess": "true"
-      };
-
       // table with role of grid
-      testAbsentAttrs("table1", attr);
+      isDataTable("table1");
       // table with role of grid and datatable="0"
-      testAbsentAttrs("table1.1", attr);
+      isDataTable("table1.1");
 
       // table with landmark role
-      testAbsentAttrs("table2", attr);
+      isDataTable("table2");
 
       // table with summary
-      testAbsentAttrs("table3", attr);
+      isDataTable("table3");
 
       // table with caption
-      testAbsentAttrs("table4", attr);
+      isDataTable("table4");
 
       // layout table with empty caption
-      testAttrs("table4.2", attr, true);
+      isLayoutTable("table4.2");
 
       // table with thead element
-      testAbsentAttrs("table5", attr);
+      isDataTable("table5");
 
       // table with tfoot element
-      testAbsentAttrs("table5.1", attr);
+      isDataTable("table5.1");
 
       // table with colgroup or col elements
-      testAbsentAttrs("table5.2", attr);
-      testAbsentAttrs("table5.3", attr);
+      isDataTable("table5.2");
+      isDataTable("table5.3");
 
       // table with th element
-      testAbsentAttrs("table6", attr);
+      isDataTable("table6");
 
       // table with headers attribute
-      testAbsentAttrs("table6.2", attr);
+      isDataTable("table6.2");
 
       // table with scope attribute
-      testAbsentAttrs("table6.2.2", attr);
+      isDataTable("table6.2.2");
 
       // table with abbr attribute
-      testAbsentAttrs("table6.2.3", attr);
+      isDataTable("table6.2.3");
 
       // table with abbr element
-      testAbsentAttrs("table6.3", attr);
+      isDataTable("table6.3");
 
       // table with abbr element having empty text node
-      testAbsentAttrs("table6.4", attr);
+      isDataTable("table6.4");
 
       // table with abbr element and non-empty text node
-      testAttrs("table6.5", attr, true);
+      isLayoutTable("table6.5");
 
       // layout table with nested table
-      testAttrs("table9", attr, true);
+      isLayoutTable("table9");
 
       // layout table with 1 column
-      testAttrs("table10", attr, true);
+      isLayoutTable("table10");
 
       // layout table with 1 row
-      testAttrs("table11", attr, true);
+      isLayoutTable("table11");
 
       // table with 5 columns
-      testAbsentAttrs("table12", attr);
+      isDataTable("table12");
 
       // table with a bordered cell
-      testAbsentAttrs("table13", attr);
+      isDataTable("table13");
 
       // table with alternating row background colors
-      testAbsentAttrs("table14", attr);
+      isDataTable("table14");
 
       // table with 3 columns and 21 rows
-      testAbsentAttrs("table15", attr);
+      isDataTable("table15");
 
       // layout table that has a 100% width
-      testAttrs("table16", attr, true);
+      isLayoutTable("table16");
 
       // layout table that has a 95% width in pixels
-      testAttrs("table17", attr, true);
+      isLayoutTable("table17");
 
       // layout table with less than 10 columns
-      testAttrs("table18", attr, true);
+      isLayoutTable("table18");
 
       // layout table with embedded iframe
-      testAttrs("table19", attr, true);
+      isLayoutTable("table19");
 
       // tree grid, no layout table
-      testAbsentAttrs("table20", attr);
+      isDataTable("table20");
 
       // layout table containing nested data table (having data structures)
-      testAttrs("table21", attr, true);
-      testAttrs("table21.2", attr, true);
-      testAttrs("table21.3", attr, true);
-      testAttrs("table21.4", attr, true);
-      testAttrs("table21.5", attr, true);
-      testAttrs("table21.6", attr, true);
+      isLayoutTable("table21");
+      isLayoutTable("table21.2");
+      isLayoutTable("table21.3");
+      isLayoutTable("table21.4");
+      isLayoutTable("table21.5");
+      isLayoutTable("table21.6");
 
       // layout table having datatable="0" attribute and containing data table structure (tfoot element)
-      testAttrs("table22", attr, true);
+      isLayoutTable("table22");
+
+      // layout display:block table with 1 column
+      isLayoutTable("displayblock_table1");
+
+      // matrix
+      isDataTable("mtable1");
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
@@ -496,10 +504,37 @@
   <table id="table22" datatable="0">
     <tfoot>
       <tr>
         <td>Cell1</td><td>cell2</td>
       </tr>
     </tfoot>
   </table>
 
+  <!-- display:block table -->
+  <table id="displayblock_table1" style="display:block">
+    <tr><td>Row1</td></tr>
+    <tr><td>Row2</td></tr>
+  </table>
+
+  <!-- MathML matrix -->
+  <math>
+    <mtable id="mtable1">
+      <mtr>
+        <mtd>
+          <mn>1</mn>
+        </mtd>
+        <mtd>
+          <mn>0</mn>
+        </mtd>
+      </mtr>
+      <mtr>
+        <mtd>
+          <mn>0</mn>
+        </mtd>
+        <mtd>
+          <mn>1</mn>
+        </mtd>
+      </mtr>
+    </mtable>
+  </math>
 </body>
 </html>