diff --git a/dom/html/HTMLTableElement.cpp b/dom/html/HTMLTableElement.cpp
index 9d414a98d729..52a87bec01f6 100644
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -60,17 +60,11 @@ protected:
// Those rows that are not in table sections
HTMLTableElement* mParent;
- RefPtr mOrphanRows;
};
TableRowsCollection::TableRowsCollection(HTMLTableElement *aParent)
: mParent(aParent)
- , mOrphanRows(new nsContentList(mParent,
- kNameSpaceID_XHTML,
- nsGkAtoms::tr,
- nsGkAtoms::tr,
- false))
{
}
@@ -88,7 +82,7 @@ TableRowsCollection::WrapObject(JSContext* aCx, JS::Handle aGivenProt
return HTMLCollectionBinding::Wrap(aCx, this, aGivenProto);
}
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TableRowsCollection, mOrphanRows)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(TableRowsCollection)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)
@@ -101,48 +95,54 @@ NS_INTERFACE_MAP_END
// Macro that can be used to avoid copy/pasting code to iterate over the
// rowgroups. _code should be the code to execute for each rowgroup. The
-// rowgroup's rows will be in the nsIDOMHTMLCollection* named "rows". Note
-// that this may be null at any time. This macro assumes an nsresult named
+// rowgroup's rows will be in the nsIDOMHTMLCollection* named "rows".
+// _trCode should be the code to execute for each tr row. Note that
+// this may be null at any time. This macro assumes an nsresult named
// |rv| is in scope.
-#define DO_FOR_EACH_ROWGROUP(_code) \
- do { \
- if (mParent) { \
- /* THead */ \
- HTMLTableSectionElement* rowGroup = mParent->GetTHead(); \
- nsIHTMLCollection* rows; \
- if (rowGroup) { \
- rows = rowGroup->Rows(); \
- do { /* gives scoping */ \
- _code \
- } while (0); \
- } \
- /* TBodies */ \
- for (nsIContent* _node = mParent->nsINode::GetFirstChild(); \
- _node; _node = _node->GetNextSibling()) { \
- if (_node->IsHTMLElement(nsGkAtoms::tbody)) { \
- rowGroup = static_cast(_node); \
- rows = rowGroup->Rows(); \
- do { /* gives scoping */ \
- _code \
- } while (0); \
+ #define DO_FOR_EACH_BY_ORDER(_code, _trCode) \
+ do { \
+ if (mParent) { \
+ HTMLTableSectionElement* rowGroup; \
+ nsIHTMLCollection* rows; \
+ /* THead */ \
+ for (nsIContent* _node = mParent->nsINode::GetFirstChild(); \
+ _node; _node = _node->GetNextSibling()) { \
+ if (_node->IsHTMLElement(nsGkAtoms::thead)) { \
+ rowGroup = static_cast(_node);\
+ rows = rowGroup->Rows(); \
+ do { /* gives scoping */ \
+ _code \
+ } while (0); \
+ } \
+ } \
+ /* TBodies */ \
+ for (nsIContent* _node = mParent->nsINode::GetFirstChild(); \
+ _node; _node = _node->GetNextSibling()) { \
+ if (_node->IsHTMLElement(nsGkAtoms::tr)) { \
+ do { \
+ _trCode \
+ } while (0); \
+ } else if (_node->IsHTMLElement(nsGkAtoms::tbody)) { \
+ rowGroup = static_cast(_node); \
+ rows = rowGroup->Rows(); \
+ do { /* gives scoping */ \
+ _code \
+ } while (0); \
+ } \
+ } \
+ /* TFoot */ \
+ for (nsIContent* _node = mParent->nsINode::GetFirstChild(); \
+ _node; _node = _node->GetNextSibling()) { \
+ if (_node->IsHTMLElement(nsGkAtoms::tfoot)) { \
+ rowGroup = static_cast(_node);\
+ rows = rowGroup->Rows(); \
+ do { /* gives scoping */ \
+ _code \
+ } while (0); \
+ } \
} \
} \
- /* orphan rows */ \
- rows = mOrphanRows; \
- do { /* gives scoping */ \
- _code \
- } while (0); \
- /* TFoot */ \
- rowGroup = mParent->GetTFoot(); \
- rows = nullptr; \
- if (rowGroup) { \
- rows = rowGroup->Rows(); \
- do { /* gives scoping */ \
- _code \
- } while (0); \
- } \
- } \
- } while (0)
+ } while (0)
static uint32_t
CountRowsInRowGroup(nsIDOMHTMLCollection* rows)
@@ -164,9 +164,11 @@ TableRowsCollection::GetLength(uint32_t* aLength)
{
*aLength=0;
- DO_FOR_EACH_ROWGROUP(
+ DO_FOR_EACH_BY_ORDER({
*aLength += CountRowsInRowGroup(rows);
- );
+ }, {
+ (*aLength)++;
+ });
return NS_OK;
}
@@ -194,7 +196,7 @@ GetItemOrCountInRowGroup(nsIDOMHTMLCollection* rows,
Element*
TableRowsCollection::GetElementAt(uint32_t aIndex)
{
- DO_FOR_EACH_ROWGROUP(
+ DO_FOR_EACH_BY_ORDER({
uint32_t count;
Element* node = GetItemOrCountInRowGroup(rows, aIndex, &count);
if (node) {
@@ -203,7 +205,12 @@ TableRowsCollection::GetElementAt(uint32_t aIndex)
NS_ASSERTION(count <= aIndex, "GetItemOrCountInRowGroup screwed up");
aIndex -= count;
- );
+ },{
+ if (aIndex == 0) {
+ return _node->AsElement();
+ }
+ aIndex--;
+ });
return nullptr;
}
@@ -225,19 +232,30 @@ Element*
TableRowsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound)
{
aFound = false;
- DO_FOR_EACH_ROWGROUP(
+ nsCOMPtr nameAtom = NS_Atomize(aName);
+ NS_ENSURE_TRUE(nameAtom, nullptr);
+ DO_FOR_EACH_BY_ORDER({
Element* item = rows->NamedGetter(aName, aFound);
if (aFound) {
return item;
}
- );
+ }, {
+ if (_node->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
+ nameAtom, eCaseMatters) ||
+ _node->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
+ nameAtom, eCaseMatters)) {
+ aFound = true;
+ return _node->AsElement();
+ }
+ });
+
return nullptr;
}
void
TableRowsCollection::GetSupportedNames(nsTArray& aNames)
{
- DO_FOR_EACH_ROWGROUP(
+ DO_FOR_EACH_BY_ORDER({
nsTArray names;
nsCOMPtr coll = do_QueryInterface(rows);
if (coll) {
@@ -248,7 +266,31 @@ TableRowsCollection::GetSupportedNames(nsTArray& aNames)
}
}
}
- );
+ }, {
+ if (_node->HasID()) {
+ nsIAtom* idAtom = _node->GetID();
+ MOZ_ASSERT(idAtom != nsGkAtoms::_empty,
+ "Empty ids don't get atomized");
+ nsDependentAtomString idStr(idAtom);
+ if (!aNames.Contains(idStr)) {
+ aNames.AppendElement(idStr);
+ }
+ }
+
+ nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(_node);
+ if (el) {
+ const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
+ if (val && val->Type() == nsAttrValue::eAtom) {
+ nsIAtom* nameAtom = val->GetAtomValue();
+ MOZ_ASSERT(nameAtom != nsGkAtoms::_empty,
+ "Empty names don't get atomized");
+ nsDependentAtomString nameStr(nameAtom);
+ if (!aNames.Contains(nameStr)) {
+ aNames.AppendElement(nameStr);
+ }
+ }
+ }
+ });
}
@@ -256,18 +298,15 @@ NS_IMETHODIMP
TableRowsCollection::NamedItem(const nsAString& aName,
nsIDOMNode** aReturn)
{
- DO_FOR_EACH_ROWGROUP(
- nsCOMPtr collection = do_QueryInterface(rows);
- if (collection) {
- nsresult rv = collection->NamedItem(aName, aReturn);
- if (NS_FAILED(rv) || *aReturn) {
- return rv;
- }
- }
- );
+ bool found;
+ nsISupports* node = GetFirstNamedElement(aName, found);
+ if (!node) {
+ *aReturn = nullptr;
- *aReturn = nullptr;
- return NS_OK;
+ return NS_OK;
+ }
+
+ return CallQueryInterface(node, aReturn);
}
NS_IMETHODIMP
diff --git a/testing/web-platform/meta/html/semantics/tabular-data/the-table-element/table-rows.html.ini b/testing/web-platform/meta/html/semantics/tabular-data/the-table-element/table-rows.html.ini
deleted file mode 100644
index 4370c22560cb..000000000000
--- a/testing/web-platform/meta/html/semantics/tabular-data/the-table-element/table-rows.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[table-rows.html]
- type: testharness
- [Complicated case]
- expected: FAIL
-
diff --git a/testing/web-platform/tests/html/semantics/tabular-data/the-table-element/table-rows.html b/testing/web-platform/tests/html/semantics/tabular-data/the-table-element/table-rows.html
index c813e0866e64..8bc23d5a7c45 100644
--- a/testing/web-platform/tests/html/semantics/tabular-data/the-table-element/table-rows.html
+++ b/testing/web-platform/tests/html/semantics/tabular-data/the-table-element/table-rows.html
@@ -34,6 +34,14 @@ function test_table_simple(group, table) {
assert_equals(table.rows.bar, bar1);
assert_equals(table.rows["bar"], bar1);
assert_equals(table.rows.namedItem("bar"), bar1);
+ assert_array_equals(Object.getOwnPropertyNames(table.rows), [
+ "0",
+ "1",
+ "2",
+ "3",
+ "foo",
+ "bar"
+ ]);
}
test(function() {
var table = document.createElement("table");
@@ -145,6 +153,46 @@ test(function() {
foot2row1,
foot2row2
]);
+ assert_array_equals(Object.getOwnPropertyNames(table.rows), [
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "head1row1",
+ "head1row2",
+ "head2row1",
+ "head2row2",
+ "orphan1",
+ "orphan2",
+ "orphan3",
+ "body1row1",
+ "body1row2",
+ "orphan4",
+ "body2row1",
+ "body2row2",
+ "orphan5",
+ "orphan6",
+ "orphan7",
+ "foot1row1",
+ "foot1row2",
+ "foot2row1",
+ "foot2row2"
+ ]);
var ids = [
"orphan1",