--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1158,28 +1158,29 @@ static nsresult FireEventForAccessibilit
const nsAString& aEventType);
#endif
//
// construction, destruction
//
HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
- FromParser aFromParser)
+ FromParser aFromParser, FromClone aFromClone)
: nsGenericHTMLFormElementWithState(aNodeInfo)
, mType(kInputDefaultType->value)
, mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown)
, mDisabledChanged(false)
, mValueChanged(false)
, mLastValueChangeWasInteractive(false)
, mCheckedChanged(false)
, mChecked(false)
, mHandlingSelectEvent(false)
, mShouldInitChecked(false)
- , mParserCreating(aFromParser != NOT_FROM_PARSER)
+ , mDoneCreating(aFromParser == NOT_FROM_PARSER &&
+ aFromClone == FromClone::no)
, mInInternalActivate(false)
, mCheckedIsToggled(false)
, mIndeterminate(false)
, mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT)
, mCanShowValidUI(true)
, mCanShowInvalidUI(true)
, mHasRange(false)
, mIsDraggingRange(false)
@@ -1304,17 +1305,18 @@ NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_S
// nsIDOMNode
nsresult
HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const
{
*aResult = nullptr;
already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
- RefPtr<HTMLInputElement> it = new HTMLInputElement(ni, NOT_FROM_PARSER);
+ RefPtr<HTMLInputElement> it = new HTMLInputElement(ni, NOT_FROM_PARSER,
+ FromClone::yes);
nsresult rv = const_cast<HTMLInputElement*>(this)->CopyInnerTo(it);
NS_ENSURE_SUCCESS(rv, rv);
switch (GetValueMode()) {
case VALUE_MODE_VALUE:
if (mValueChanged) {
// We don't have our default value anymore. Set our value on
@@ -1346,36 +1348,38 @@ HTMLInputElement::Clone(mozilla::dom::No
break;
case VALUE_MODE_DEFAULT:
if (mType == NS_FORM_INPUT_IMAGE && it->OwnerDoc()->IsStaticDocument()) {
CreateStaticImageClone(it);
}
break;
}
+ it->DoneCreatingElement();
+
it->mLastValueChangeWasInteractive = mLastValueChangeWasInteractive;
it.forget(aResult);
return NS_OK;
}
nsresult
HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
//
// When name or type changes, radio should be removed from radio group.
// (type changes are handled in the form itself currently)
- // If the parser is not done creating the radio, we also should not do it.
+ // If we are not done creating the radio, we also should not do it.
//
if ((aName == nsGkAtoms::name ||
(aName == nsGkAtoms::type && !mForm)) &&
mType == NS_FORM_INPUT_RADIO &&
- (mForm || !mParserCreating)) {
+ (mForm || mDoneCreating)) {
WillRemoveFromRadioGroup();
} else if (aNotify && aName == nsGkAtoms::src &&
mType == NS_FORM_INPUT_IMAGE) {
if (aValue) {
LoadImage(aValue->String(), true, aNotify, eImageLoadType_Normal);
} else {
// Null value means the attr got unset; drop the image
CancelImageRequests(aNotify);
@@ -1410,22 +1414,22 @@ HTMLInputElement::BeforeSetAttr(int32_t
nsresult
HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
//
// When name or type changes, radio should be added to radio group.
// (type changes are handled in the form itself currently)
- // If the parser is not done creating the radio, we also should not do it.
+ // If we are not done creating the radio, we also should not do it.
//
if ((aName == nsGkAtoms::name ||
(aName == nsGkAtoms::type && !mForm)) &&
mType == NS_FORM_INPUT_RADIO &&
- (mForm || !mParserCreating)) {
+ (mForm || mDoneCreating)) {
AddedToRadioGroup();
UpdateValueMissingValidityStateForRadio(false);
}
// If @value is changed and BF_VALUE_CHANGED is false, @value is the value
// of the element so, if the value of the element is different than @value,
// we have to re-set it. This is only the case when GetValueMode() returns
// VALUE_MODE_VALUE.
@@ -1433,19 +1437,19 @@ HTMLInputElement::AfterSetAttr(int32_t a
!mValueChanged && GetValueMode() == VALUE_MODE_VALUE) {
SetDefaultValueAsValue();
}
//
// Checked must be set no matter what type of control it is, since
// mChecked must reflect the new value
if (aName == nsGkAtoms::checked && !mCheckedChanged) {
- // Delay setting checked if the parser is creating this element (wait
+ // Delay setting checked if we are creating this element (wait
// until everything is set)
- if (mParserCreating) {
+ if (!mDoneCreating) {
mShouldInitChecked = true;
} else {
DoSetChecked(DefaultChecked(), true, true);
SetCheckedChanged(false);
}
}
if (aName == nsGkAtoms::type) {
@@ -1489,17 +1493,17 @@ HTMLInputElement::AfterSetAttr(int32_t a
// This *has* to be called *after* validity has changed.
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
}
} else if (MinOrMaxLengthApplies() && aName == nsGkAtoms::maxlength) {
UpdateTooLongValidityState();
} else if (MinOrMaxLengthApplies() && aName == nsGkAtoms::minlength) {
UpdateTooShortValidityState();
- } else if (aName == nsGkAtoms::pattern && !mParserCreating) {
+ } else if (aName == nsGkAtoms::pattern && mDoneCreating) {
UpdatePatternMismatchValidityState();
} else if (aName == nsGkAtoms::multiple) {
UpdateTypeMismatchValidityState();
} else if (aName == nsGkAtoms::max) {
UpdateHasRange();
if (mType == NS_FORM_INPUT_RANGE) {
// The value may need to change when @max changes since the value may
// have been invalid and can now change to a valid value, or vice
@@ -1515,52 +1519,52 @@ HTMLInputElement::AfterSetAttr(int32_t a
nsAutoString value;
GetValue(value);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
}
// Validity state must be updated *after* the SetValueInternal call above
// or else the following assert will not be valid.
- // We don't assert the state of underflow during parsing since
+ // We don't assert the state of underflow during creation since
// DoneCreatingElement sanitizes.
UpdateRangeOverflowValidityState();
- MOZ_ASSERT(mParserCreating ||
+ MOZ_ASSERT(!mDoneCreating ||
mType != NS_FORM_INPUT_RANGE ||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
"HTML5 spec does not allow underflow for type=range");
} else if (aName == nsGkAtoms::min) {
UpdateHasRange();
if (mType == NS_FORM_INPUT_RANGE) {
// See @max comment
nsAutoString value;
GetValue(value);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
}
// See corresponding @max comment
UpdateRangeUnderflowValidityState();
UpdateStepMismatchValidityState();
- MOZ_ASSERT(mParserCreating ||
+ MOZ_ASSERT(!mDoneCreating ||
mType != NS_FORM_INPUT_RANGE ||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
"HTML5 spec does not allow underflow for type=range");
} else if (aName == nsGkAtoms::step) {
if (mType == NS_FORM_INPUT_RANGE) {
// See @max comment
nsAutoString value;
GetValue(value);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
}
// See corresponding @max comment
UpdateStepMismatchValidityState();
- MOZ_ASSERT(mParserCreating ||
+ MOZ_ASSERT(!mDoneCreating ||
mType != NS_FORM_INPUT_RANGE ||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
"HTML5 spec does not allow underflow for type=range");
} else if (aName == nsGkAtoms::dir &&
aValue && aValue->Equals(nsGkAtoms::_auto, eIgnoreCase)) {
SetDirectionIfAuto(true, aNotify);
} else if (aName == nsGkAtoms::lang) {
if (mType == NS_FORM_INPUT_NUMBER) {
@@ -3244,32 +3248,32 @@ HTMLInputElement::SetValueInternal(const
switch (GetValueMode()) {
case VALUE_MODE_VALUE:
{
// At the moment, only single line text control have to sanitize their value
// Because we have to create a new string for that, we should prevent doing
// it if it's useless.
nsAutoString value(aValue);
- if (!mParserCreating) {
+ if (mDoneCreating) {
SanitizeValue(value);
}
- // else DoneCreatingElement calls us again once mParserCreating is false
+ // else DoneCreatingElement calls us again once mDoneCreating is true
bool setValueChanged = !!(aFlags & nsTextEditorState::eSetValue_Notify);
if (setValueChanged) {
SetValueChanged(true);
}
if (IsSingleLineTextControl(false)) {
if (!mInputData.mState->SetValue(value, aFlags)) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (mType == NS_FORM_INPUT_EMAIL) {
- UpdateAllValidityStates(mParserCreating);
+ UpdateAllValidityStates(!mDoneCreating);
}
} else {
free(mInputData.mValue);
mInputData.mValue = ToNewUnicode(value);
if (setValueChanged) {
SetValueChanged(true);
}
if (mType == NS_FORM_INPUT_NUMBER) {
@@ -3287,21 +3291,21 @@ HTMLInputElement::SetValueInternal(const
}
} else if (mType == NS_FORM_INPUT_TIME &&
!IsExperimentalMobileType(mType)) {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->UpdateInputBoxValue();
}
}
- if (!mParserCreating) {
+ if (mDoneCreating) {
OnValueChanged(/* aNotify = */ true,
/* aWasInteractiveUserChange = */ false);
}
- // else DoneCreatingElement calls us again once mParserCreating is false
+ // else DoneCreatingElement calls us again once mDoneCreating is true
}
if (mType == NS_FORM_INPUT_COLOR) {
// Update color frame, to reflect color changes
nsColorControlFrame* colorControlFrame = do_QueryFrame(GetPrimaryFrame());
if (colorControlFrame) {
colorControlFrame->UpdateColor();
}
@@ -5159,17 +5163,17 @@ HTMLInputElement::HandleTypeChange(uint8
UpdateAllValidityStates(false);
UpdateApzAwareFlag();
}
void
HTMLInputElement::SanitizeValue(nsAString& aValue)
{
- NS_ASSERTION(!mParserCreating, "The element parsing should be finished!");
+ NS_ASSERTION(mDoneCreating, "The element creation should be finished!");
switch (mType) {
case NS_FORM_INPUT_TEXT:
case NS_FORM_INPUT_SEARCH:
case NS_FORM_INPUT_TEL:
case NS_FORM_INPUT_PASSWORD:
{
char16_t crlf[] = { char16_t('\r'), char16_t('\n'), 0 };
@@ -6707,17 +6711,17 @@ HTMLInputElement::SaveState()
}
return NS_OK;
}
void
HTMLInputElement::DoneCreatingElement()
{
- mParserCreating = false;
+ mDoneCreating = true;
//
// Restore state as needed. Note that disabled state applies to all control
// types.
//
bool restoredCheckedState =
!mInhibitRestoration && NS_SUCCEEDED(GenerateStateKey()) && RestoreFormControlState();
@@ -6943,18 +6947,18 @@ void
HTMLInputElement::AddedToRadioGroup()
{
// If the element is neither in a form nor a document, there is no group so we
// should just stop here.
if (!mForm && !IsInUncomposedDoc()) {
return;
}
- // Make sure not to notify if we're still being created by the parser
- bool notify = !mParserCreating;
+ // Make sure not to notify if we're still being created
+ bool notify = mDoneCreating;
//
// If the input element is checked, and we add it to the group, it will
// deselect whatever is currently selected in that group
//
if (mChecked) {
//
// If it is checked, call "RadioSetChecked" to perform the selection/
@@ -7705,17 +7709,17 @@ void
HTMLInputElement::UpdateTooShortValidityState()
{
SetValidityState(VALIDITY_STATE_TOO_SHORT, IsTooShort());
}
void
HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
{
- bool notify = !mParserCreating;
+ bool notify = mDoneCreating;
nsCOMPtr<nsIDOMHTMLInputElement> selection = GetSelectedRadioButton();
aIgnoreSelf = aIgnoreSelf || !IsMutable();
// If there is no selection, that might mean the radio is not in a group.
// In that case, we can look for the checked state of the radio.
bool selected = selection || (!aIgnoreSelf && mChecked);
bool required = !aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required);
@@ -8228,17 +8232,17 @@ HTMLInputElement::GetRows()
NS_IMETHODIMP_(void)
HTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
{
nsTextEditorState *state = GetEditorState();
if (state) {
GetDefaultValue(aValue);
// This is called by the frame to show the value.
// We have to sanitize it when needed.
- if (!mParserCreating) {
+ if (mDoneCreating) {
SanitizeValue(aValue);
}
}
}
NS_IMETHODIMP_(bool)
HTMLInputElement::ValueChanged() const
{