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",