Closed Bug 1264947 Opened 9 years ago Closed 9 years ago

HTMLTableElement.rows doesn't seem to return element in the order defined in HTML Spec.

Categories

(Core :: DOM: Core & HTML, defect)

36 Branch
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla49
Tracking Status
firefox49 --- fixed

People

(Reporter: smaug, Assigned: jdai)

Details

(Whiteboard: [tw-dom] btpp-active)

Attachments

(4 files, 8 obsolete files)

775 bytes, text/html
Details
1.53 KB, text/html
Details
6.58 KB, patch
jdai
: review+
Details | Diff | Splinter Review
14.93 KB, patch
jdai
: review+
Details | Diff | Splinter Review
If I read the code right, the implementation returns first elements in tbodies, and then children of table element itself. Per spec "followed by those elements whose parent is either a table or tbody element, again in tree order,"
Need to test what other browsers do.
Attached file test
And we're behavior differently to Edge and Chrome. I assume fixing this should be quite easy. Some changes to #define DO_FOR_EACH_ROWGROUP(_code) in HTMLTableElement.cpp We probably need separate macro/method to find certain element based on an index and then the existing macro works for a fast way to get the length of the collection. Or something, could be fixed also in different way.
Whiteboard: [tw-dom]
(In reply to Olli Pettay [:smaug] from comment #3) > And we're behavior differently to Edge and Chrome. huh, how did I write that bad English :) Anyhow, link to the spec https://html.spec.whatwg.org/multipage/tables.html#dom-table-rows
Assignee: nobody → jdai
Attached file test2
Whiteboard: [tw-dom] → [tw-dom] btpp-active
Attachment #8750192 - Attachment description: Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order. → wip, v1
Attachment #8750192 - Attachment is obsolete: true
Comment on attachment 8750638 [details] [diff] [review] Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order. Base on comment #3, I separate a macro named DO_FOR_EACH_BY_ORDER() which is to find certain element based on an index. Hi Olli, may I have your review? Thank you.
Attachment #8750638 - Attachment description: wip, v2 → Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order.
Attachment #8750638 - Flags: review?(bugs)
Attachment #8750191 - Flags: review?(bugs)
Attachment #8750191 - Flags: review?(bugs) → review+
Looks like no, since that test fails because of some issue in head/foot handling. I wonder if that is issue in the test or in the spec or in our impl.
Comment on attachment 8750638 [details] [diff] [review] Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order. yeah, looks like we just handle the first thead and first tfoot, but per spec .rows should handle them all. So the macro here cann't use mParent->GetTHead()/GetTFoot() but needs to actually iterate through all the child node for those. And once that is done, the wpt test should pass and the .ini file which annotates known failures could be removed.
Attachment #8750638 - Flags: review?(bugs) → review-
Address comment 10, which are - Make all the tests in table-rows.html are passed. - Modify TableRowsCollection::GetLength() apply DO_FOR_EACH_BY_ORDER(). - Remove test_bug1264947.html because wpt table-rows.html cover all of them. Try result:https://treeherder.mozilla.org/#/jobs?repo=try&revision=d914eb7fb451ee44831f032bec1e630dd921ac4a Hi Olli, may I have your review? Thank you.
Attachment #8750638 - Attachment is obsolete: true
Attachment #8751150 - Flags: review?(bugs)
Now that I look at the code some more, do we ever need to use DO_FOR_EACH_ROWGROUP, or should we always use the new macro? In other words, could or should TableRowsCollection::GetSupportedNames and TableRowsCollection::NamedItem use the new macro? I think so.
Flags: needinfo?(jdai)
(In reply to Olli Pettay [:smaug] from comment #14) > Now that I look at the code some more, do we ever need to use > DO_FOR_EACH_ROWGROUP, or should we always use the new macro? > In other words, could or should TableRowsCollection::GetSupportedNames and > TableRowsCollection::NamedItem use the new macro? I think so. Yes, you are right. We should use new macro. Thank you for pointing them out. Looks like TableRowsCollection::NamedItem no method use it, perhaps I should add comment for it?
Flags: needinfo?(jdai)
I'm pretty sure the generated code for HTMLCollection webidl interface uses NamedItem.
Address comment 14, which is - Apply TableRowsCollection::GetSupportedNames and TableRowsCollection::NamedItem to new macro.
Attachment #8751150 - Attachment is obsolete: true
Attachment #8751150 - Flags: review?(bugs)
Following comment 17, I removed mOrphanRows in this patch. Hi Olli, may I have your review? Thank you.
Attachment #8751603 - Attachment is obsolete: true
Attachment #8752045 - Flags: review?(bugs)
Comment on attachment 8752045 [details] [diff] [review] Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order. v4 > // 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 excute for each tr row. Note that execute >+// 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<HTMLTableSectionElement*>(_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<HTMLTableSectionElement*>(_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); \ >+ } \ >+ if (_node->IsHTMLElement(nsGkAtoms::tbody)) { \ This 'if' could be 'else if', right? > TableRowsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound) > { > aFound = false; >- DO_FOR_EACH_ROWGROUP( >+ DO_FOR_EACH_BY_ORDER({ > Element* item = rows->NamedGetter(aName, aFound); > if (aFound) { > return item; > } >- ); >+ }, { >+ nsCOMPtr<nsIAtom> name = NS_Atomize(aName); >+ NS_ENSURE_TRUE(name, nullptr); Perhaps move this atomize to be before the macro usage so that we don't repeat it for each <tr> elements. >+ if (_node && >+ ((_node->IsHTMLElement() && Is there a need for _node->IsHTMLElement() check here. Don't we do that inside the macro since we have if (_node->IsHTMLElement(nsGkAtoms::tr)) { there. >+ _node->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, >+ name, eCaseMatters)) || 2 spaces too much before 'name' >+ _node->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, >+ name, eCaseMatters))) { ditto > TableRowsCollection::GetSupportedNames(nsTArray<nsString>& aNames) > { >- DO_FOR_EACH_ROWGROUP( >+ AutoTArray<nsIAtom*, 8> atoms; >+ DO_FOR_EACH_BY_ORDER({ > nsTArray<nsString> names; > nsCOMPtr<nsIHTMLCollection> coll = do_QueryInterface(rows); > if (coll) { > coll->GetSupportedNames(names); > for (uint32_t i = 0; i < names.Length(); ++i) { > if (!aNames.Contains(names[i])) { > aNames.AppendElement(names[i]); > } > } > } >- ); >+ }, { >+ if (_node->HasID()) { >+ nsIAtom* id = _node->GetID(); >+ MOZ_ASSERT(id != nsGkAtoms::_empty, >+ "Empty ids don't get atomized"); >+ if (!atoms.Contains(id)) { >+ atoms.AppendElement(id); >+ } >+ } >+ >+ nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(_node); >+ if (el) { >+ const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name); >+ if (val && val->Type() == nsAttrValue::eAtom) { >+ nsIAtom* name = val->GetAtomValue(); >+ MOZ_ASSERT(name != nsGkAtoms::_empty, >+ "Empty names don't get atomized"); >+ if (!atoms.Contains(name)) { >+ atoms.AppendElement(name); >+ } >+ } >+ } >+ >+ uint32_t atomsLen = atoms.Length(); >+ >+ nsString* names = aNames.AppendElements(atomsLen); >+ for (uint32_t i = 0; i < atomsLen; ++i) { >+ atoms[i]->ToString(names[i]); >+ } What if aNames already contains the name, I mean what if it has been added there already in the block which deals with rows. I think it would be simpler if you just played with strings here and not have separate array for atoms. Note, if you need to convert atom to string for comparisons etc, nsDependentAtomString can be handy. I'd like to see a new patch fixing TableRowsCollection::GetSupportedNames.
Attachment #8752045 - Flags: review?(bugs) → review-
Thanks for your useful information. I address it all and add a testcase in my patch. Hi Olli, may I have your review? Thank you.
Attachment #8752045 - Attachment is obsolete: true
Attachment #8752761 - Flags: review?(bugs)
Comment on attachment 8752761 [details] [diff] [review] Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order. v5 > TableRowsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound) > { > aFound = false; >- DO_FOR_EACH_ROWGROUP( >+ nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(aName); >+ DO_FOR_EACH_BY_ORDER({ > Element* item = rows->NamedGetter(aName, aFound); > if (aFound) { > return item; > } >- ); >+ }, { >+ NS_ENSURE_TRUE(nameAtom, nullptr); move also this NS_ENSURE_TRUE to be next to NS_Atomize(aName); >+++ b/dom/html/test/test_bug1264947.html You could have added all the new tests to the existing web-platform-test, but up to you.
Attachment #8752761 - Flags: review?(bugs) → review+
(In reply to Olli Pettay [:smaug] from comment #21) > Comment on attachment 8752761 [details] [diff] [review] > Part 2: Bug 1264947 - HTMLTableElement.rows return element in the order. v5 > > > TableRowsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound) > > { > > aFound = false; > >- DO_FOR_EACH_ROWGROUP( > >+ nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(aName); > >+ DO_FOR_EACH_BY_ORDER({ > > Element* item = rows->NamedGetter(aName, aFound); > > if (aFound) { > > return item; > > } > >- ); > >+ }, { > >+ NS_ENSURE_TRUE(nameAtom, nullptr); > move also this NS_ENSURE_TRUE to be next to NS_Atomize(aName); Will do. > > >+++ b/dom/html/test/test_bug1264947.html > You could have added all the new tests to the existing web-platform-test, > but up to you. I will put my tests into existing web-platform-test. Thank you.
I upload a new patch because the previous patch missed part of code. Try result: https://treeherder.mozilla.org/#/jobs?repo=try&revision=f4fea5191a556bf31cfe9a22ed75d09fd8d44cfc
Attachment #8753294 - Attachment is obsolete: true
Attachment #8753301 - Flags: review+
Keywords: checkin-needed
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla49
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: