Do not dispatch 'change' event if the INPUT value is not changed.

This CL fixes two problems.

* When the INPUT type is changed, m_textAsOfLastFormControlChangeEvent is not
  initialized correctly.  So, we dispatched unexpected change events.

* When readonly/disabled state is changed, we call
  SpinButtonElement::releaseCapture(), which can dispatch a 'change' event. Its
  callsite should protect |this|.

BUG=454231,455193

Review URL: https://codereview.chromium.org/880473005

git-svn-id: svn://svn.chromium.org/blink/trunk@189774 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-disabled-crash-expected.txt b/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-disabled-crash-expected.txt
new file mode 100644
index 0000000..018565b
--- /dev/null
+++ b/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-disabled-crash-expected.txt
@@ -0,0 +1,11 @@
+CONSOLE WARNING: The specified value 'a' does not conform to the required format, 'yyyy-MM-dd'.
+Date input with invalid initial value should not dispatch a change event on disabled=true, and should not crash.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS changeEventCounter is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-disabled-crash.html b/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-disabled-crash.html
new file mode 100644
index 0000000..9e13e91
--- /dev/null
+++ b/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-disabled-crash.html
@@ -0,0 +1,20 @@
+<body>
+<script src="../../../resources/js-test.js"></script>
+<form>
+<input value="a" id="input1">
+</form>
+<script>
+description('Date input with invalid initial value should not dispatch a change event on disabled=true, and should not crash.');
+var changeEventCounter = 0;
+var input1 = document.querySelector('#input1');
+input1.type = 'date';
+input1.addEventListener('change', function handleChange() {
+  ++changeEventCounter;
+  input1.removeEventListener('change', handleChange);
+  input1.type = 'search';
+}, false);
+input1.disabled = true;
+shouldBe('changeEventCounter', '0');
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/number/number-change-event-by-readonly-expected.txt b/LayoutTests/fast/forms/number/number-change-event-by-readonly-expected.txt
new file mode 100644
index 0000000..20580981
--- /dev/null
+++ b/LayoutTests/fast/forms/number/number-change-event-by-readonly-expected.txt
@@ -0,0 +1,10 @@
+Read-only number input should not dispatch a change event.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS changeEventCounter is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/forms/number/number-change-event-by-readonly.html b/LayoutTests/fast/forms/number/number-change-event-by-readonly.html
new file mode 100644
index 0000000..e092a99
--- /dev/null
+++ b/LayoutTests/fast/forms/number/number-change-event-by-readonly.html
@@ -0,0 +1,11 @@
+<script src="../../../resources/js-test.js"></script>
+<script>
+description('Read-only number input should not dispatch a change event.');
+var changeEventCounter = 0;
+function handleChange() {
+    ++changeEventCounter;
+}
+var parent = document.createElement('div');
+parent.innerHTML = '<input type="number" value="0" onchange="handleChange()" readonly>';
+shouldBe('changeEventCounter', '0');
+</script>
diff --git a/Source/core/html/HTMLInputElement.cpp b/Source/core/html/HTMLInputElement.cpp
index 2385f43..7fe7b74 100644
--- a/Source/core/html/HTMLInputElement.cpp
+++ b/Source/core/html/HTMLInputElement.cpp
@@ -444,6 +444,8 @@
     m_inputType->warnIfValueIsInvalid(fastGetAttribute(valueAttr).string());
 
     m_inputTypeView->updateView();
+    setTextAsOfLastFormControlChangeEvent(value());
+    setChangedSinceLastFormControlChangeEvent(false);
 }
 
 void HTMLInputElement::updateType()
@@ -508,6 +510,7 @@
     if (document().focusedElement() == this)
         document().updateFocusAppearanceSoon(true /* restore selection */);
 
+    setTextAsOfLastFormControlChangeEvent(value());
     setChangedSinceLastFormControlChangeEvent(false);
 
     addToRadioButtonGroup();
diff --git a/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp b/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
index c76f9f6..4088373 100644
--- a/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
+++ b/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
@@ -419,6 +419,7 @@
 
 void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged()
 {
+    EventQueueScope scope;
     spinButtonElement()->releaseCapture();
     if (DateTimeEditElement* edit = dateTimeEditElement())
         edit->disabledStateChanged();
@@ -464,6 +465,7 @@
 
 void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged()
 {
+    EventQueueScope scope;
     spinButtonElement()->releaseCapture();
     if (DateTimeEditElement* edit = dateTimeEditElement())
         edit->readOnlyStateChanged();