Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: Source/core/html/HTMLFormControlElement.cpp

Issue 672163002: Fix bug where form/fieldset :valid/:invalid won't be recalculated upon control's willValidate change Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Add layout tests to catch the problem Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 { 261 {
262 fieldSetAncestorsSetNeedsValidityCheck(insertionPoint); 262 fieldSetAncestorsSetNeedsValidityCheck(insertionPoint);
263 hideVisibleValidationMessage(); 263 hideVisibleValidationMessage();
264 m_hasValidationMessage = false; 264 m_hasValidationMessage = false;
265 m_ancestorDisabledState = AncestorDisabledStateUnknown; 265 m_ancestorDisabledState = AncestorDisabledStateUnknown;
266 m_dataListAncestorState = Unknown; 266 m_dataListAncestorState = Unknown;
267 HTMLElement::removedFrom(insertionPoint); 267 HTMLElement::removedFrom(insertionPoint);
268 FormAssociatedElement::removedFrom(insertionPoint); 268 FormAssociatedElement::removedFrom(insertionPoint);
269 } 269 }
270 270
271 void HTMLFormControlElement::willChangeForm() 271 void HTMLFormControlElement::didChangeForm(HTMLFormElement* oldForm)
272 { 272 {
273 formOwnerSetNeedsValidityCheck(); 273 FormAssociatedElement::didChangeForm(oldForm);
274 FormAssociatedElement::willChangeForm(); 274 if (oldForm)
275 oldForm->setNeedsValidityCheck(ElementRemoval, isValidElement());
276 formOwnerSetNeedsValidityCheck(ElementAddition, isValidElement());
275 } 277 }
276 278
277 void HTMLFormControlElement::didChangeForm() 279 void HTMLFormControlElement::formOwnerSetNeedsValidityCheck(ValidityChangeAction action, bool isValid)
278 {
279 formOwnerSetNeedsValidityCheck();
280 FormAssociatedElement::didChangeForm();
281 }
282
283 void HTMLFormControlElement::formOwnerSetNeedsValidityCheck()
284 { 280 {
285 HTMLFormElement* form = formOwner(); 281 HTMLFormElement* form = formOwner();
286 if (form) 282 if (form)
287 form->setNeedsValidityCheck(); 283 form->setNeedsValidityCheck(action, isValid);
288 } 284 }
289 285
290 void HTMLFormControlElement::fieldSetAncestorsSetNeedsValidityCheck(Node* node) 286 void HTMLFormControlElement::fieldSetAncestorsSetNeedsValidityCheck(Node* node)
291 { 287 {
292 if (!node) 288 if (!node)
293 return; 289 return;
294 HTMLFieldSetElement* fieldSet = Traversal<HTMLFieldSetElement>::firstAncesto rOrSelf(*node); 290 HTMLFieldSetElement* fieldSet = Traversal<HTMLFieldSetElement>::firstAncesto rOrSelf(*node);
295 HTMLFieldSetElement* lastFieldSet = 0; 291 HTMLFieldSetElement* lastFieldSet = 0;
296 while (fieldSet) { 292 while (fieldSet) {
297 lastFieldSet = fieldSet; 293 lastFieldSet = fieldSet;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 { 399 {
404 if (m_dataListAncestorState == Unknown) { 400 if (m_dataListAncestorState == Unknown) {
405 if (Traversal<HTMLDataListElement>::firstAncestor(*this)) 401 if (Traversal<HTMLDataListElement>::firstAncestor(*this))
406 m_dataListAncestorState = InsideDataList; 402 m_dataListAncestorState = InsideDataList;
407 else 403 else
408 m_dataListAncestorState = NotInsideDataList; 404 m_dataListAncestorState = NotInsideDataList;
409 } 405 }
410 return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly (); 406 return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly ();
411 } 407 }
412 408
409 bool HTMLFormControlElement::refreshWillValidate()
410 {
411 bool newWillValidate = recalcWillValidate();
412 if (m_willValidateInitialized && m_willValidate == newWillValidate)
413 return false;
414 m_willValidateInitialized = true;
415 m_willValidate = newWillValidate;
416 // Use m_isValid, because isValidElement() calls valid(), which in turn can
417 // call willValidate() again.
keishi 2014/10/24 10:25:49 Is this true? m_willValidateInitialized is set to
Bartek Nowierski 2014/10/24 10:48:30 It's a little more complex than that. Calling isVa
keishi 2014/10/24 11:07:17 I think using ElementAddition/Removal here when we
Bartek Nowierski 2014/10/24 14:47:16 Done.
418 formOwnerSetNeedsValidityCheck(newWillValidate ? ElementAddition : ElementRe moval, m_isValid);
419 fieldSetAncestorsSetNeedsValidityCheck(parentNode());
420 setNeedsValidityCheck();
421 return true;
422 }
423
413 bool HTMLFormControlElement::willValidate() const 424 bool HTMLFormControlElement::willValidate() const
414 { 425 {
415 if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) { 426 if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
416 m_willValidateInitialized = true; 427 const_cast<HTMLFormControlElement*>(this)->refreshWillValidate();
417 bool newWillValidate = recalcWillValidate();
418 if (m_willValidate != newWillValidate) {
419 m_willValidate = newWillValidate;
420 const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck();
421 }
422 } else { 428 } else {
423 // If the following assertion fails, setNeedsWillValidateCheck() is not 429 // If the following assertion fails, setNeedsWillValidateCheck() is not
424 // called correctly when something which changes recalcWillValidate() re sult 430 // called correctly when something which changes recalcWillValidate() re sult
425 // is updated. 431 // is updated.
426 ASSERT(m_willValidate == recalcWillValidate()); 432 ASSERT(m_willValidate == recalcWillValidate());
427 } 433 }
428 return m_willValidate; 434 return m_willValidate;
429 } 435 }
430 436
431 void HTMLFormControlElement::setNeedsWillValidateCheck() 437 void HTMLFormControlElement::setNeedsWillValidateCheck()
432 { 438 {
433 // We need to recalculate willValidate immediately because willValidate chan ge can causes style change. 439 // We need to recalculate willValidate immediately because willValidate chan ge can causes style change.
434 bool newWillValidate = recalcWillValidate(); 440 if (refreshWillValidate())
435 if (m_willValidateInitialized && m_willValidate == newWillValidate) 441 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::cre ate(StyleChangeReason::Validate));
436 return;
437 m_willValidateInitialized = true;
438 m_willValidate = newWillValidate;
439 setNeedsValidityCheck();
440 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create( StyleChangeReason::Validate));
441 if (!m_willValidate) 442 if (!m_willValidate)
442 hideVisibleValidationMessage(); 443 hideVisibleValidationMessage();
443 } 444 }
444 445
445 void HTMLFormControlElement::findCustomValidationMessageTextDirection(const Stri ng& message, TextDirection &messageDir, String& subMessage, TextDirection &subMe ssageDir) 446 void HTMLFormControlElement::findCustomValidationMessageTextDirection(const Stri ng& message, TextDirection &messageDir, String& subMessage, TextDirection &subMe ssageDir)
446 { 447 {
447 bool hasStrongDirection; 448 bool hasStrongDirection;
448 subMessage = fastGetAttribute(titleAttr); 449 subMessage = fastGetAttribute(titleAttr);
449 messageDir = determineDirectionality(message, hasStrongDirection); 450 messageDir = determineDirectionality(message, hasStrongDirection);
450 if (!subMessage.isEmpty()) 451 if (!subMessage.isEmpty())
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 { 558 {
558 // If the following assertion fails, setNeedsValidityCheck() is not called 559 // If the following assertion fails, setNeedsValidityCheck() is not called
559 // correctly when something which changes validity is updated. 560 // correctly when something which changes validity is updated.
560 ASSERT(m_isValid == valid()); 561 ASSERT(m_isValid == valid());
561 return m_isValid; 562 return m_isValid;
562 } 563 }
563 564
564 void HTMLFormControlElement::setNeedsValidityCheck() 565 void HTMLFormControlElement::setNeedsValidityCheck()
565 { 566 {
566 bool newIsValid = valid(); 567 bool newIsValid = valid();
567 if (willValidate() && newIsValid != m_isValid) { 568 bool changed = newIsValid != m_isValid;
568 formOwnerSetNeedsValidityCheck(); 569 m_isValid = newIsValid;
570 if (willValidate() && changed) {
571 formOwnerSetNeedsValidityCheck(ElementModification, newIsValid);
569 fieldSetAncestorsSetNeedsValidityCheck(parentNode()); 572 fieldSetAncestorsSetNeedsValidityCheck(parentNode());
570 // Update style for pseudo classes such as :valid :invalid. 573 // Update style for pseudo classes such as :valid :invalid.
571 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::cre ateWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Invalid)) ; 574 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::cre ateWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Invalid)) ;
572 } 575 }
573 m_isValid = newIsValid;
574 576
575 // Updates only if this control already has a validation message. 577 // Updates only if this control already has a validation message.
576 if (isValidationMessageVisible()) { 578 if (isValidationMessageVisible()) {
577 // Calls updateVisibleValidationMessage() even if m_isValid is not 579 // Calls updateVisibleValidationMessage() even if m_isValid is not
578 // changed because a validation message can be changed. 580 // changed because a validation message can be changed.
579 updateVisibleValidationMessage(); 581 updateVisibleValidationMessage();
580 } 582 }
581 } 583 }
582 584
583 void HTMLFormControlElement::setCustomValidity(const String& error) 585 void HTMLFormControlElement::setCustomValidity(const String& error)
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 624
623 void HTMLFormControlElement::setFocus(bool flag) 625 void HTMLFormControlElement::setFocus(bool flag)
624 { 626 {
625 LabelableElement::setFocus(flag); 627 LabelableElement::setFocus(flag);
626 628
627 if (!flag && wasChangedSinceLastFormControlChangeEvent()) 629 if (!flag && wasChangedSinceLastFormControlChangeEvent())
628 dispatchFormControlChangeEvent(); 630 dispatchFormControlChangeEvent();
629 } 631 }
630 632
631 } // namespace blink 633 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698