Current behavoir: The :empty selector matches every element. Reason: The reason for this is that every time a new element is added to the DOM, it is checked to see if it matches one of the CSS selectors. Because the DOM is build one element at a time, every element is at least for a brief moment empty. Proper behavoir: The :empty selector should only match elements that are *really* empty. Once an element is no longer empty it should no longer match this selector.
I think Test 37 in Acid3 is hitting this bug.
Created attachment 18798 [details] test case
Currently it's a test 38 in Acid3: function () { // test 38: :empty selectorTest(function (doc, add, expect) { var empty = add(":empty"); var p = doc.createElement('p'); doc.body.appendChild(p); expect(p, empty, "empty element didn't match :empty"); var span = doc.createElement('span'); p.appendChild(span); expect(p, 0, "removing all children didn't make the element match :empty"); p.removeChild(span); p.appendChild(doc.createComment("c")); p.appendChild(doc.createTextNode("a")); expect(p, 0, "element with no child element nodes didn't match :empty"); }); return 3; },
Wow, that test had errors. Fixed. Doesn't affect this bug, though.
Created attachment 18831 [details] Patch that implements dynamic :empty
Comment on attachment 18831 [details] Patch that implements dynamic :empty The formatting change in CSSStyleSelector::locateSharedStyleseems unnecessary. This looks good to me, but given mitz spotted the issue with comment nodes breaking the hasChildNodes() == style->emptyState() check and i didn't, i figure i'll leave this to him.
Comment on attachment 18831 [details] Patch that implements dynamic :empty r=me with the condition changed to (!style->emptyState() || hasChildNodes()).
Created attachment 18840 [details] Revised patch with refinements from Acid3 testing.
Comment on attachment 18840 [details] Revised patch with refinements from Acid3 testing. r=me
Fixed in r29918.