Backed out changeset 013278adabc7 (bug 1837540) for build bustages on mochitest.ini . CLOSED TREE

This commit is contained in:
Narcis Beleuzu 2023-08-03 02:25:53 +03:00
parent eff3063bb2
commit 53cd71602f
11 changed files with 112 additions and 202 deletions

View File

@ -606,7 +606,7 @@ class Document : public nsINode,
aFocusedRadio, aRadioOut);
}
void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio) final {
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio, nullptr);
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
}
void RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) final {

View File

@ -115,11 +115,9 @@ nsresult RadioGroupManager::GetNextRadioButton(const nsAString& aName,
}
void RadioGroupManager::AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio,
nsIContent* aAncestor) {
HTMLInputElement* aRadio) {
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
nsContentUtils::AddElementToListByTreeOrder(radioGroup->mRadioButtons, aRadio,
aAncestor);
radioGroup->mRadioButtons.AppendElement(aRadio);
if (aRadio->IsRequired()) {
radioGroup->mRequiredRadioCount++;

View File

@ -12,8 +12,6 @@
#include "nsIRadioGroupContainer.h"
#include "nsClassHashtable.h"
class nsIContent;
namespace mozilla {
namespace html {
@ -39,8 +37,7 @@ class RadioGroupManager {
nsresult GetNextRadioButton(const nsAString& aName, const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut);
void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio,
nsIContent* aAncestor);
void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio);
void RemoveFromRadioGroup(const nsAString& aName, HTMLInputElement* aRadio);
uint32_t GetRequiredRadioCount(const nsAString& aName) const;
void RadioRequiredWillChange(const nsAString& aName, bool aRequiredAdded);

View File

@ -255,7 +255,7 @@ class ShadowRoot final : public DocumentFragment,
}
void AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) override {
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio, this);
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
}
void RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) override {

View File

@ -175,7 +175,6 @@
#include "mozilla/dom/FromParser.h"
#include "mozilla/dom/HTMLElement.h"
#include "mozilla/dom/HTMLFormElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/HTMLTextAreaElement.h"
#include "mozilla/dom/IPCBlob.h"
@ -11226,84 +11225,6 @@ nsIContent* nsContentUtils::GetClosestLinkInFlatTree(nsIContent* aContent) {
return nullptr;
}
namespace {
struct TreePositionComparator {
Element* const mChild;
nsIContent* const mAncestor;
TreePositionComparator(Element* aChild, nsIContent* aAncestor)
: mChild(aChild), mAncestor(aAncestor) {}
int operator()(Element* aElement) const {
return nsLayoutUtils::CompareTreePosition(mChild, aElement, mAncestor);
}
};
} // namespace
/* static */
int32_t nsContentUtils::CompareTreePosition(nsIContent* aContent1,
nsIContent* aContent2,
const nsIContent* aCommonAncestor) {
NS_ASSERTION(aContent1 != aContent2, "Comparing content to itself");
// TODO: remove the prevent asserts fix, see bug 598468.
#ifdef DEBUG
nsLayoutUtils::gPreventAssertInCompareTreePosition = true;
int32_t rVal =
nsLayoutUtils::CompareTreePosition(aContent1, aContent2, aCommonAncestor);
nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
return rVal;
#else // DEBUG
return nsLayoutUtils::CompareTreePosition(aContent1, aContent2,
aCommonAncestor);
#endif // DEBUG
}
/* static */
template <typename ElementType, typename ElementPtr>
bool nsContentUtils::AddElementToListByTreeOrder(nsTArray<ElementType>& aList,
ElementPtr aChild,
nsIContent* aCommonAncestor) {
NS_ASSERTION(aList.IndexOf(aChild) == aList.NoIndex,
"aChild already in aList");
const uint32_t count = aList.Length();
ElementType element;
// Optimize most common case where we insert at the end.
int32_t position = -1;
if (count > 0) {
element = aList[count - 1];
position = CompareTreePosition(aChild, element, aCommonAncestor);
}
// If this item comes after the last element, or the elements array is
// empty, we append to the end. Otherwise, we do a binary search to
// determine where the element should go.
if (position >= 0 || count == 0) {
aList.AppendElement(aChild);
return true;
}
size_t idx;
BinarySearchIf(aList, 0, count,
TreePositionComparator(aChild, aCommonAncestor), &idx);
aList.InsertElementAt(idx, aChild);
return false;
}
template bool nsContentUtils::AddElementToListByTreeOrder(
nsTArray<nsGenericHTMLFormElement*>& aList,
nsGenericHTMLFormElement* aChild, nsIContent* aAncestor);
template bool nsContentUtils::AddElementToListByTreeOrder(
nsTArray<HTMLImageElement*>& aList, HTMLImageElement* aChild,
nsIContent* aAncestor);
template bool nsContentUtils::AddElementToListByTreeOrder(
nsTArray<RefPtr<HTMLInputElement>>& aList, HTMLInputElement* aChild,
nsIContent* aAncestor);
namespace mozilla {
std::ostream& operator<<(std::ostream& aOut,
const PreventDefaultResult aPreventDefaultResult) {

View File

@ -3435,33 +3435,6 @@ class nsContentUtils {
static bool IsExternalProtocol(nsIURI* aURI);
/**
* Add an element to a list, keeping the list sorted by tree order.
* Can take a potential ancestor of the elements in order to speed up
* tree-order comparisons, if such an ancestor exists.
* Returns true if the element is appended to the end of the list.
*/
template <typename ElementType, typename ElementPtr>
static bool AddElementToListByTreeOrder(nsTArray<ElementType>& aList,
ElementPtr aChild,
nsIContent* aCommonAncestor);
/**
* Compares the position of aContent1 and aContent2 in the document
* @param aContent1 First content to compare.
* @param aContent2 Second content to compare.
* @param aCommonAncestor Potential ancestor of the contents, if one exists.
* This is only a hint; if it's not an ancestor of
* aContent1 or aContent2, this function will still
* work, but it will be slower than normal.
* @return < 0 if aContent1 is before aContent2,
* > 0 if aContent1 is after aContent2,
* 0 otherwise
*/
static int32_t CompareTreePosition(nsIContent* aContent1,
nsIContent* aContent2,
const nsIContent* aCommonAncestor);
private:
static bool InitializeEventTable();

View File

@ -222,9 +222,9 @@ nsresult HTMLFormControlsCollection::GetSortedControls(
// Determine which of the two elements should be ordered
// first and add it to the end of the list.
nsGenericHTMLFormElement* elementToAdd;
if (nsContentUtils::CompareTreePosition(mElements[elementsIdx],
mNotInElements[notInElementsIdx],
mForm) < 0) {
if (HTMLFormElement::CompareFormControlPosition(
mElements[elementsIdx], mNotInElements[notInElementsIdx], mForm) <
0) {
elementToAdd = mElements[elementsIdx];
++elementsIdx;
} else {

View File

@ -1086,6 +1086,44 @@ Element* HTMLFormElement::IndexedGetter(uint32_t aIndex, bool& aFound) {
return element;
}
/**
* Compares the position of aControl1 and aControl2 in the document
* @param aControl1 First control to compare.
* @param aControl2 Second control to compare.
* @param aForm Parent form of the controls.
* @return < 0 if aControl1 is before aControl2,
* > 0 if aControl1 is after aControl2,
* 0 otherwise
*/
/* static */
int32_t HTMLFormElement::CompareFormControlPosition(Element* aElement1,
Element* aElement2,
const nsIContent* aForm) {
NS_ASSERTION(aElement1 != aElement2, "Comparing a form control to itself");
// If an element has a @form, we can assume it *might* be able to not have
// a parent and still be in the form.
NS_ASSERTION(
(aElement1->HasAttr(nsGkAtoms::form) || aElement1->GetParent()) &&
(aElement2->HasAttr(nsGkAtoms::form) || aElement2->GetParent()),
"Form controls should always have parents");
// If we pass aForm, we are assuming both controls are form descendants which
// is not always the case. This function should work but maybe slower.
// However, checking if both elements are form descendants may be slow too...
// TODO: remove the prevent asserts fix, see bug 598468.
#ifdef DEBUG
nsLayoutUtils::gPreventAssertInCompareTreePosition = true;
int32_t rVal =
nsLayoutUtils::CompareTreePosition(aElement1, aElement2, aForm);
nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
return rVal;
#else // DEBUG
return nsLayoutUtils::CompareTreePosition(aElement1, aElement2, aForm);
#endif // DEBUG
}
#ifdef DEBUG
/**
* Checks that all form elements are in document order. Asserts if any pair of
@ -1168,6 +1206,58 @@ void HTMLFormElement::PostPossibleUsernameEvent() {
mFormPossibleUsernameEventDispatcher->PostDOMEvent();
}
namespace {
struct FormComparator {
Element* const mChild;
HTMLFormElement* const mForm;
FormComparator(Element* aChild, HTMLFormElement* aForm)
: mChild(aChild), mForm(aForm) {}
int operator()(Element* aElement) const {
return HTMLFormElement::CompareFormControlPosition(mChild, aElement, mForm);
}
};
} // namespace
// This function return true if the element, once appended, is the last one in
// the array.
template <typename ElementType>
static bool AddElementToList(nsTArray<ElementType*>& aList, ElementType* aChild,
HTMLFormElement* aForm) {
NS_ASSERTION(aList.IndexOf(aChild) == aList.NoIndex,
"aChild already in aList");
const uint32_t count = aList.Length();
ElementType* element;
bool lastElement = false;
// Optimize most common case where we insert at the end.
int32_t position = -1;
if (count > 0) {
element = aList[count - 1];
position =
HTMLFormElement::CompareFormControlPosition(aChild, element, aForm);
}
// If this item comes after the last element, or the elements array is
// empty, we append to the end. Otherwise, we do a binary search to
// determine where the element should go.
if (position >= 0 || count == 0) {
// WEAK - don't addref
aList.AppendElement(aChild);
lastElement = true;
} else {
size_t idx;
BinarySearchIf(aList, 0, count, FormComparator(aChild, aForm), &idx);
// WEAK - don't addref
aList.InsertElementAt(idx, aChild);
}
return lastElement;
}
nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
bool aUpdateValidity, bool aNotify) {
// If an element has a @form, we can assume it *might* be able to not have
@ -1182,8 +1272,7 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
nsTArray<nsGenericHTMLFormElement*>& controlList =
childInElements ? mControls->mElements : mControls->mNotInElements;
bool lastElement =
nsContentUtils::AddElementToListByTreeOrder(controlList, aChild, this);
bool lastElement = AddElementToList(controlList, aChild, this);
#ifdef DEBUG
AssertDocumentOrder(controlList, this);
@ -1219,16 +1308,16 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
// what's in the slot or the child is earlier than the default submit.
nsGenericHTMLFormElement* oldDefaultSubmit = mDefaultSubmitElement;
if (!*firstSubmitSlot ||
(!lastElement && nsContentUtils::CompareTreePosition(
aChild, *firstSubmitSlot, this) < 0)) {
(!lastElement &&
CompareFormControlPosition(aChild, *firstSubmitSlot, this) < 0)) {
// Update mDefaultSubmitElement if it's currently in a valid state.
// Valid state means either non-null or null because there are in fact
// no submit elements around.
if ((mDefaultSubmitElement ||
(!mFirstSubmitInElements && !mFirstSubmitNotInElements)) &&
(*firstSubmitSlot == mDefaultSubmitElement ||
nsContentUtils::CompareTreePosition(aChild, mDefaultSubmitElement,
this) < 0)) {
CompareFormControlPosition(aChild, mDefaultSubmitElement, this) <
0)) {
mDefaultSubmitElement = aChild;
}
*firstSubmitSlot = aChild;
@ -1359,8 +1448,8 @@ void HTMLFormElement::HandleDefaultSubmitRemoval() {
"How did that happen?");
// Have both; use the earlier one
mDefaultSubmitElement =
nsContentUtils::CompareTreePosition(mFirstSubmitInElements,
mFirstSubmitNotInElements, this) < 0
CompareFormControlPosition(mFirstSubmitInElements,
mFirstSubmitNotInElements, this) < 0
? mFirstSubmitInElements
: mFirstSubmitNotInElements;
}
@ -1708,8 +1797,8 @@ bool HTMLFormElement::IsDefaultSubmitElement(
// We have both kinds of submits. Check which comes first.
nsGenericHTMLFormElement* defaultSubmit =
nsContentUtils::CompareTreePosition(mFirstSubmitInElements,
mFirstSubmitNotInElements, this) < 0
CompareFormControlPosition(mFirstSubmitInElements,
mFirstSubmitNotInElements, this) < 0
? mFirstSubmitInElements
: mFirstSubmitNotInElements;
return aElement == defaultSubmit;
@ -1922,7 +2011,7 @@ HTMLFormElement::WalkRadioGroup(const nsAString& aName,
void HTMLFormElement::AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) {
RadioGroupManager::AddToRadioGroup(aName, aRadio, this);
RadioGroupManager::AddToRadioGroup(aName, aRadio);
}
void HTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
@ -2078,7 +2167,7 @@ nsresult HTMLFormElement::AddElementToTableInternal(
}
nsresult HTMLFormElement::AddImageElement(HTMLImageElement* aChild) {
nsContentUtils::AddElementToListByTreeOrder(mImageElements, aChild, this);
AddElementToList(mImageElements, aChild, this);
return NS_OK;
}

View File

@ -379,6 +379,9 @@ class HTMLFormElement final : public nsGenericHTMLElement,
void GetSupportedNames(nsTArray<nsString>& aRetval);
static int32_t CompareFormControlPosition(Element* aElement1,
Element* aElement2,
const nsIContent* aForm);
#ifdef DEBUG
static void AssertDocumentOrder(
const nsTArray<nsGenericHTMLFormElement*>& aControls, nsIContent* aForm);

View File

@ -14,7 +14,6 @@ prefs =
[test_bug1286509.html]
[test_button_attributes_reflection.html]
[test_input_radio_indeterminate.html]
[test_input_radio_navigation_order.html]
[test_input_radio_radiogroup.html]
[test_input_radio_required.html]
[test_change_event.html]

View File

@ -1,70 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Radio button group keyboard navigation order</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
</head>
<body>
<form id="inside">
<input type="radio" name="inside" id="inside1"/>
<input type="radio" name="inside" id="inside2"/>
<input type="radio" name="inside" id="inside3"/>
</form>
<form id="before"></form>
<input type="radio" form="before" name="before" id="before1"/>
<input type="radio" form="before" name="before" id="before2"/>
<input type="radio" form="before" name="before" id="before3"/>
<input type="radio" form="after" name="after" id="after1"/>
<input type="radio" form="after" name="after" id="after2"/>
<input type="radio" form="after" name="after" id="after3"/>
<form id="after"></form>
<input type="radio" name="mix" id="mix1"/>
<form id="mix"><input type="radio" name="mix" id="mix2"/></form>
<input type="radio" name="mix" id="mix3"/>
<input type="radio" name="doc" id="doc1"/>
<input type="radio" name="doc" id="doc2"/>
<input type="radio" name="doc" id="doc3"/>
<script>
async function pressRight() {
return new test_driver.Actions()
.keyDown("\uE014")
.keyUp("\uE014")
.send();
}
promise_test(async () => {
for (const groupName of ["inside", "before", "after", "mix", "doc"]) {
const firstInGroup = document.querySelector(`input[name="${groupName}"]`);
const newInput = document.createElement("input");
newInput.id = groupName + "New";
newInput.type = "radio";
if (groupName != "doc") {
newInput.setAttribute("form", groupName);
}
newInput.name = groupName;
firstInGroup.after(newInput);
}
for (const formId of ["inside", "before", "after", "mix"]) {
document.forms[formId].elements[0].focus();
for (const radio of document.forms[formId].elements) {
assert_equals(radio, document.activeElement, `Navigated to next radio button in form '${formId}'`);
await pressRight();
}
}
const radios = document.querySelectorAll("input[name='doc']");
radios[0].focus();
for (const radio of radios) {
assert_equals(radio, document.activeElement, `Navigated to next radio button on document`);
await pressRight();
}
}, "Radio button keyboard navigation should proceed in tree-order.");
</script>
</body>
</html>