Bug 45719

Summary: A radio button not in a Document should not join a radio button group
Product: WebKit Reporter: Joel <joel>
Component: FormsAssignee: Kent Tamura <tkent>
Status: RESOLVED FIXED    
Severity: Normal CC: ap, darin, dglazkov, ljharb, my.shin, tkent, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
URL: http://leosciencelab.com/1.php
Bug Depends on: 76051    
Bug Blocks: 74909    
Attachments:
Description Flags
proposed patch
eric: review-
proposed patch(2nd)
none
WIP
none
Patch by tkent
none
Patch by tkent
none
Patch by tkent 3
none
Patch by tkent 4
none
Patch by tkent 5 darin: review+

Description Joel 2010-09-13 16:32:13 PDT
http://le.bytestudios.com/1.php


$('body').append('<label><input checked="checked" type="radio" name="checkme">I should be checked</label>');

only if you have a name attribute, the checkbox will not be checked after this is run.
if you remove the name attribute everything works fine.
this can be seen on chrome as well.
windows and mac.

this works:
$('body').append('<label><input checked="checked" type="radio">I am checked</label>');
Comment 1 Alexey Proskuryakov 2010-09-15 10:27:35 PDT
See also: bug 34520, bug 37900.
Comment 2 My Shin 2010-12-08 20:28:41 PST
Created attachment 76008 [details]
proposed patch

I upload patch. please review it.
Comment 3 Eric Seidel (no email) 2010-12-12 02:15:04 PST
Comment on attachment 76008 [details]
proposed patch

I don't think attached() is the check you want here. You want to know if it's in a document, not if it has a renderer.
Comment 4 Joel 2010-12-12 09:13:00 PST
(In reply to comment #0)

http://leosciencelab.com/1.php is the new location
Comment 5 My Shin 2010-12-13 18:14:25 PST
Created attachment 76478 [details]
proposed patch(2nd)

I changed the condition, 'attach()', to 'renderer()'. Thank your comment.
please review again.
Comment 6 Dimitri Glazkov (Google) 2011-01-25 21:22:28 PST
Comment on attachment 76478 [details]
proposed patch(2nd)

View in context: https://bugs.webkit.org/attachment.cgi?id=76478&action=review

Also needs to be rebased for after the big Source move.

> WebCore/html/HTMLInputElement.cpp:685
> +        if (renderer())

This is wrong. You can also have a NULL renderer() if you set display:none. eseidel suggested earlier that you're probably looking for inDocument: http://www.google.com/codesearch/p#OAMlx_jo-ck/src/third_party/WebKit/WebCore/dom/Node.h&l=361&exact_package=chromium

> LayoutTests/fast/forms/radio-checked-by-javascript.html:31
> +    document.write("This should be checked");

document.write? ew.

> LayoutTests/fast/forms/radio-checked-by-javascript.html:39
> +var radioElement1, radioElement2, radioElement3, radioElement4;

no need to declare this outside of the function. Could just do var el = document.getElementById('foo');

> LayoutTests/fast/forms/radio-checked-by-javascript.html:41
> +    radioElement1 = document.getElementById('radioID1');

Can you make this into a helper function that gets an element and verifies if the element is checked? This way you would have a much more elegant code.
Comment 7 Kent Tamura 2011-12-21 23:55:38 PST
*** Bug 74642 has been marked as a duplicate of this bug. ***
Comment 8 Kent Tamura 2011-12-21 23:59:48 PST
I'll handle this.
Comment 9 Kent Tamura 2011-12-22 02:41:44 PST
Created attachment 120294 [details]
WIP
Comment 10 WebKit Review Bot 2011-12-22 03:42:49 PST
Comment on attachment 120294 [details]
WIP

Attachment 120294 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/10998415

New failing tests:
fast/forms/removed-image-as-property.html
Comment 11 Kent Tamura 2011-12-25 23:37:19 PST
Created attachment 120532 [details]
Patch by tkent
Comment 12 Kent Tamura 2011-12-26 00:25:04 PST
Created attachment 120535 [details]
Patch by tkent

rebased
Comment 13 Darin Adler 2011-12-26 07:10:59 PST
Comment on attachment 120535 [details]
Patch by tkent

View in context: https://bugs.webkit.org/attachment.cgi?id=120535&action=review

I am not sure we have enough test coverage. Given what I see here in the code, I suspect that radio buttons end up stuck in groups when they should not be there.

> Source/WebCore/dom/CheckedRadioButtons.cpp:72
> -void CheckedRadioButtons::removeButton(HTMLFormControlElement* element)
> +void CheckedRadioButtons::removeButton(HTMLInputElement* element)
>  {
> -    if (element->name().isEmpty() || !m_nameToCheckedRadioButtonMap)
> +    if (!shouldMakeRadioGroup(element))
> +        return;
> +    if (!m_nameToCheckedRadioButtonMap)
>          return;

I don’t think this function should have been changed, except for changing the type. There is no harm in removing a button from the group if it’s no longer in the document. If this is called and the element is no longer in the document, all the more reason we’d want to remove it from the checked radio button set. In fact, in HTMLInputElement::removedFromDocument, doesn’t inDocument already return false?

> Source/WebCore/html/FormAssociatedElement.cpp:125
> +    if (m_form)
> +        m_form->removeFormElement(this);

I suggest putting this into FormAssociatedElement::willChangeForm.

> Source/WebCore/html/FormAssociatedElement.cpp:128
> +    if (m_form)
> +        m_form->registerFormElement(this);

I suggest putting this into FormAssociatedElement::didChangeForm.

> Source/WebCore/html/FormAssociatedElement.cpp:136
> +    willChangeForm();

If the form has already been destroyed, then HTMLInputElement::checkedRadioButtons is going to access a deleted object. So this code won’t work!

> Source/WebCore/html/HTMLFormControlElement.cpp:53
> +    , FormAssociatedElement()

Should be able to just delete this line entirely.

> Source/WebCore/html/HTMLFormControlElement.cpp:107
>      if (attr->name() == formAttr) {
>          formAttributeChanged();
> -        if (!form())
> -            document()->checkedRadioButtons().addButton(this);
>      } else if (attr->name() == disabledAttr) {

No braces needed any more since this is now a single line if body.

> Source/WebCore/html/HTMLInputElement.cpp:1500
> +    checkedRadioButtons().removeButton(this);

This should call through to the base class.

> Source/WebCore/html/HTMLInputElement.cpp:1505
> +    checkedRadioButtons().addButton(this);

This should call through to the base class.
Comment 14 Kent Tamura 2012-01-04 23:43:02 PST
Comment on attachment 120535 [details]
Patch by tkent

View in context: https://bugs.webkit.org/attachment.cgi?id=120535&action=review

>> Source/WebCore/dom/CheckedRadioButtons.cpp:72
>>          return;
> 
> I don’t think this function should have been changed, except for changing the type. There is no harm in removing a button from the group if it’s no longer in the document. If this is called and the element is no longer in the document, all the more reason we’d want to remove it from the checked radio button set. In fact, in HTMLInputElement::removedFromDocument, doesn’t inDocument already return false?

At the beginning of HTMLInputElement::removedFromDocument(), inDocument() is still true because Node::removedFromDocument() makes it false and Node::removedFromDocument() is not called yet.  So, the patch works well.
It's ok to remove the inDocument() check.  The removal is not harmful.  However we'll have unnecessary HashMap::find() call.

>> Source/WebCore/html/FormAssociatedElement.cpp:125
>> +        m_form->removeFormElement(this);
> 
> I suggest putting this into FormAssociatedElement::willChangeForm.

will do.

>> Source/WebCore/html/FormAssociatedElement.cpp:136
>> +    willChangeForm();
> 
> If the form has already been destroyed, then HTMLInputElement::checkedRadioButtons is going to access a deleted object. So this code won’t work!

m_form is not deleted yet.  I'll rename formDestroyed() with willDestroyForm().

>> Source/WebCore/html/HTMLFormControlElement.cpp:53
>> +    , FormAssociatedElement()
> 
> Should be able to just delete this line entirely.

will do.

>> Source/WebCore/html/HTMLFormControlElement.cpp:107
>>      } else if (attr->name() == disabledAttr) {
> 
> No braces needed any more since this is now a single line if body.

will do.

>> Source/WebCore/html/HTMLInputElement.cpp:1500
>> +    checkedRadioButtons().removeButton(this);
> 
> This should call through to the base class.

will do.
Comment 15 Kent Tamura 2012-01-05 00:18:49 PST
Created attachment 121228 [details]
Patch by tkent 3
Comment 16 Kent Tamura 2012-01-05 06:32:18 PST
Created attachment 121272 [details]
Patch by tkent 4

Add more tests
Comment 17 Darin Adler 2012-01-08 20:28:47 PST
Comment on attachment 121272 [details]
Patch by tkent 4

View in context: https://bugs.webkit.org/attachment.cgi?id=121272&action=review

Overall looks good, but there is a implementation mistake (virtual functions in derived classes), and an unnecessarily complex design.

> Source/WebCore/html/FormAssociatedElement.cpp:45
> +    setForm(0);

At this point, it is too late to call virtual functions in HTMLInputElement; overrides like HTMLInputElement::willChangeForm and HTMLInputElement::didChangeForm will not get called. That’s because of how C++ destructors work. We’ll need to do this some other way.

> Source/WebCore/html/FormAssociatedElement.cpp:125
> +    willChangeForm();
> +    m_form = newForm;
> +    didChangeForm();

I think the removeFormElement and registerFormElement code should be moved into non-virtual functions, or just put inline directly into the setForm function. Then we can use a single set of virtual functions for both changing forms and disassociating with forms being destroyed. We should have just willChangeForm and didChange form.

> Source/WebCore/html/FormAssociatedElement.cpp:157
> +void FormAssociatedElement::willBeUnassociatedFromDestroyingForm()
> +{
> +}
> +
> +void FormAssociatedElement::wasUnassociatedFromDestroyingForm()
> +{
> +    ASSERT(!m_form);
>  }

A couple language nits. The verb for “association is going away” is “disassociated”. And “destroying form” is a verb phrase, not a noun phrase. So we probably need to rename these. Also, if we’re asserting !m_form in wasUnassociatedFromDestroyingForm we could also assert m_form in willBeUnassociatedFromDestroyingForm.

> Source/WebCore/html/FormAssociatedElement.h:56
> +    void willDestroyForm();

The grammar here gets twisted. Since the element will not be the one destroying the form, the function name here seems clearly wrong. I think formWillBeDestroyed is the name we should use.

And then those other functions above can be named:

    willDisassociateFormThatWillBeDestroyed
    didDisassociateFormThatWillBeDestroyed

Long unpleasant names, but the best I could do. But since my other comments say to remove these functions, I think we’ll be OK.

> Source/WebCore/html/HTMLFormElement.cpp:101
>      for (unsigned i = 0; i < m_associatedElements.size(); ++i)
> -        m_associatedElements[i]->formDestroyed();
> +        m_associatedElements[i]->willDestroyForm();

Technically, at this point the form is already partly-destroyed. We can probably get away with this fuzziness, though.

> Source/WebCore/html/HTMLInputElement.cpp:-123
> -    // Need to remove this from the form while it is still an HTMLInputElement,
> -    // so can't wait for the base class's destructor to do it.
> -    removeFromForm();

The setForm(0) call will need to be here for the same reason that removeFromForm needed to be here. The refactoring doesn’t change the basic truth that when a base class destructor is called, it can’t call virtual function overrides in derived classes.

I don’t understand why test cases failed to detect this problem.
Comment 18 Darin Adler 2012-01-08 20:28:52 PST
Comment on attachment 121272 [details]
Patch by tkent 4

View in context: https://bugs.webkit.org/attachment.cgi?id=121272&action=review

Overall looks good, but there is a implementation mistake (virtual functions in derived classes), and an unnecessarily complex design.

> Source/WebCore/html/FormAssociatedElement.cpp:45
> +    setForm(0);

At this point, it is too late to call virtual functions in HTMLInputElement; overrides like HTMLInputElement::willChangeForm and HTMLInputElement::didChangeForm will not get called. That’s because of how C++ destructors work. We’ll need to do this some other way.

> Source/WebCore/html/FormAssociatedElement.cpp:125
> +    willChangeForm();
> +    m_form = newForm;
> +    didChangeForm();

I think the removeFormElement and registerFormElement code should be moved into non-virtual functions, or just put inline directly into the setForm function. Then we can use a single set of virtual functions for both changing forms and disassociating with forms being destroyed. We should have just willChangeForm and didChange form.

> Source/WebCore/html/FormAssociatedElement.cpp:157
> +void FormAssociatedElement::willBeUnassociatedFromDestroyingForm()
> +{
> +}
> +
> +void FormAssociatedElement::wasUnassociatedFromDestroyingForm()
> +{
> +    ASSERT(!m_form);
>  }

A couple language nits. The verb for “association is going away” is “disassociated”. And “destroying form” is a verb phrase, not a noun phrase. So we probably need to rename these. Also, if we’re asserting !m_form in wasUnassociatedFromDestroyingForm we could also assert m_form in willBeUnassociatedFromDestroyingForm.

> Source/WebCore/html/FormAssociatedElement.h:56
> +    void willDestroyForm();

The grammar here gets twisted. Since the element will not be the one destroying the form, the function name here seems clearly wrong. I think formWillBeDestroyed is the name we should use.

And then those other functions above can be named:

    willDisassociateFormThatWillBeDestroyed
    didDisassociateFormThatWillBeDestroyed

Long unpleasant names, but the best I could do. But since my other comments say to remove these functions, I think we’ll be OK.

> Source/WebCore/html/HTMLFormElement.cpp:101
>      for (unsigned i = 0; i < m_associatedElements.size(); ++i)
> -        m_associatedElements[i]->formDestroyed();
> +        m_associatedElements[i]->willDestroyForm();

Technically, at this point the form is already partly-destroyed. We can probably get away with this fuzziness, though.

> Source/WebCore/html/HTMLInputElement.cpp:-123
> -    // Need to remove this from the form while it is still an HTMLInputElement,
> -    // so can't wait for the base class's destructor to do it.
> -    removeFromForm();

The setForm(0) call will need to be here for the same reason that removeFromForm needed to be here. The refactoring doesn’t change the basic truth that when a base class destructor is called, it can’t call virtual function overrides in derived classes.

I don’t understand why test cases failed to detect this problem.
Comment 19 Darin Adler 2012-01-08 20:29:14 PST
Oops, not sure why that submitted twice.
Comment 20 Kent Tamura 2012-01-09 21:10:42 PST
(In reply to comment #18)
Thank you for reviewing.

Re: setForm(0) in the destructors.

> > Source/WebCore/html/FormAssociatedElement.cpp:45
> > +    setForm(0);
> 
> At this point, it is too late to call virtual functions in HTMLInputElement; overrides like HTMLInputElement::willChangeForm and HTMLInputElement::didChangeForm will not get called. That’s because of how C++ destructors work. We’ll need to do this some other way.

Unfortunately(?), the code works well because we don't need to call CheckedRadioButtons::removeButton() from a form control destructor.
 - Usually a form control is removed from the document before being destructed. In this case, we already calls removeButton() in HTMLInputElement::removedFromDocument().
 - We can destruct a in-document from control only if the document is destructed. We don't need to call removeButton() in such case.

However not calling willChangeForm()/didChangeForm() of subclasses is very confusing and will make problems in the future.  I should change the code.


> > Source/WebCore/html/HTMLInputElement.cpp:-123
> > -    // Need to remove this from the form while it is still an HTMLInputElement,
> > -    // so can't wait for the base class's destructor to do it.
> > -    removeFromForm();
> 
> The setForm(0) call will need to be here for the same reason that removeFromForm needed to be here. The refactoring doesn’t change the basic truth that when a base class destructor is called, it can’t call virtual function overrides in derived classes.

This removeFromForm() was required because HTMLFormElement::registerFormElement() used virtual functions of HTMLInputElement for CheckedRadioButtons::removeButton().  This code is unnecessary because of the reasons same as the above.
Comment 21 Kent Tamura 2012-01-09 21:51:32 PST
Created attachment 121792 [details]
Patch by tkent 5

Remove *UnassociatedFromDestroyingForm()
Comment 22 Darin Adler 2012-01-10 10:06:57 PST
Comment on attachment 121792 [details]
Patch by tkent 5

View in context: https://bugs.webkit.org/attachment.cgi?id=121792&action=review

> Source/WebCore/ChangeLog:30
> +         Do not update m_form except in setForm() and formDestoryed().

Typo: destoryed

> Source/WebCore/ChangeLog:39
> +        This virtual function is called before the owner form is udpated.

Typo: udpated.

> Source/WebCore/ChangeLog:41
> +        This virtual function is called after the owner form was udpated.

Typo: udpated.

> Source/WebCore/ChangeLog:43
> +        - Renamaed from formDestoryed()

Typos: renamaed and destoryed.

> Source/WebCore/dom/CheckedRadioButtons.cpp:70
> +    if (!element->isRadioButton())
> +        return;

This is not needed for correctness, so I suggest we leave it out.

If you want to keep it in because it’s a performance optimization, consider that the existing checks are not performance optimizations. The empty name check below is needed, because the name is the key used in the map, so it's not a performance optimization. Same for the m_nameToCheckedRadioButtonMap check.

If we do want to improve performance here, then we could do the radio button check, but we should consider some other things as well:

1) Besides isRadioButton() we could also consider calling checked(), and use one or both depending on which are more effective at making the code faster.
2) We could change the function so that it only calls name() once, since name does both a function call and a subsequent virtual function call.
3) HTMLInputElement::name could be optimized by overriding the non-virtual name function inherited from FormAssociatedElement.

For (2), the name could be put in a local variable:

    const AtomicString& name = element->name();

since it’s used twice in the function.

For (3), HTMLInputElement could cut out the function overhead adding a non-virtual name function. Any code that has an HTMLInputElement* would then get the better performance automatically. The simplest way to write it would be:

    const AtomicString& name() { return HTMLInputElement::formElementName(); }

This would compile in a non-virtual call to the formElementName function, which is fine because classes derived from HTMLInputElement do not override formElementName. Or we could optimize even further by creating a function in HTMLInputElement that just returns m_name, since this code handles null and empty names identically. The name/formControlName function has logic to turn a null string into an empty string and we have no need for that here. These functions (either version) could be inline, and the latter one would simply be a direct accessor to a data member. Or we could change FormAssociatedElement::name and FormAssociatedElement::formControlName so that it's legal to return the null string and change the call sites that don't already cope with that.

In a mostly unrelated note, when looking at this I noticed a peculiarly-named public function, setDefaultName, that is called only by the HTMLIsIndexElement constructor. We should probably make that function protected. And further, it’s only safe to call that function if the object is not a checkbox, so we might want to assert that. And it’s only correct to call it on an object that doesn’t already have a name, so we might want to assert that m_name is null. And finally, this doesn’t actually work correctly if a name is added and then subsequently removed from the isindex element. That’s probably unimportant because of how rare it is to use the isindex element at all, but annoying that it’s incorrect. That’s the reason the function name is so bad: It doesn’t actually set a default name, just sets an initial name.

> Source/WebCore/html/FormAssociatedElement.cpp:83
>          // Resets the form owner at first to make sure the element don't
>          // associate any form elements when there is no element which has
>          // the given ID.

This comment no longer makes sense.

> Source/WebCore/html/FormAssociatedElement.cpp:88
>          Element* formElement = element->treeScope()->getElementById(element->fastGetAttribute(formAttr));
>          if (formElement && formElement->hasTagName(formTag)) {
> -            m_form = static_cast<HTMLFormElement*>(formElement);
> -            m_form->registerFormElement(this);
> +            newForm = static_cast<HTMLFormElement*>(formElement);
>          }

Should remove braces here since the function body is now one line. I think we could also consider renaming the local variable formElement, since it’s not always a form element. Might call it something like newFormCandidate.

It is wasteful that this function calls both fastHasAttribute and fastHasAttribute on the same attribute, doing a double hash table lookup. It would be more efficient to only call fastGetAttribute and check for null instead.

It would be good at some point to research if the behavior here is correct. These are the two quirks I noticed:

- If a form attribute gives an ID that is used for an object other than a form that comes earlier in the document than the form, then we don’t associate the element with the form. Even if there is also a form with that ID.
- Changes to the ID of the form or of an object other than the form that comes earlier in the document after the element is inserted into the tree have no effect.

> Source/WebCore/html/FormAssociatedElement.h:73
> +    // If you add an override of willChangeForm() or didChangeForm() to a
> +    // subclass, you need to add setForm(0) to the destructor of the subclass.

Would be better to use the formal C++ term, “class derived from this one” or “derived class”, rather than “subclass”.

I’d say “If you add an override of willChangeForm() or didChangeForm() to a class derived from this one, you will need to add a call to setForm(0) to the destructor of that class".
Comment 23 Darin Adler 2012-01-10 10:08:53 PST
(In reply to comment #20)
> Re: setForm(0) in the destructors.
> 
> > > Source/WebCore/html/FormAssociatedElement.cpp:45
> > > +    setForm(0);
> > 
> > At this point, it is too late to call virtual functions in HTMLInputElement; overrides like HTMLInputElement::willChangeForm and HTMLInputElement::didChangeForm will not get called. That’s because of how C++ destructors work. We’ll need to do this some other way.
> 
> Unfortunately(?), the code works well because we don't need to call CheckedRadioButtons::removeButton() from a form control destructor.
>  - Usually a form control is removed from the document before being destructed. In this case, we already calls removeButton() in HTMLInputElement::removedFromDocument().
>  - We can destruct a in-document from control only if the document is destructed. We don't need to call removeButton() in such case.

If the setForm(0) is really effectively dead code, then we could consider an improved design where it’s not needed, replaced with an assertion or something along those lines.
Comment 24 Kent Tamura 2012-01-10 20:08:12 PST
Comment on attachment 121792 [details]
Patch by tkent 5

View in context: https://bugs.webkit.org/attachment.cgi?id=121792&action=review

>> Source/WebCore/ChangeLog:30
>> +         Do not update m_form except in setForm() and formDestoryed().
> 
> Typo: destoryed

Corrected: formDestoryed() -> formWillBeDestroyed()

>> Source/WebCore/ChangeLog:39
>> +        This virtual function is called before the owner form is udpated.
> 
> Typo: udpated.

Corrected.

>> Source/WebCore/ChangeLog:41
>> +        This virtual function is called after the owner form was udpated.
> 
> Typo: udpated.

Corrected.

>> Source/WebCore/ChangeLog:43
>> +        - Renamaed from formDestoryed()
> 
> Typos: renamaed and destoryed.

Corrected.

>> Source/WebCore/html/FormAssociatedElement.cpp:83
>>          // the given ID.
> 
> This comment no longer makes sense.

Removed.

>> Source/WebCore/html/FormAssociatedElement.cpp:88
>>          }
> 
> Should remove braces here since the function body is now one line. I think we could also consider renaming the local variable formElement, since it’s not always a form element. Might call it something like newFormCandidate.
> 
> It is wasteful that this function calls both fastHasAttribute and fastHasAttribute on the same attribute, doing a double hash table lookup. It would be more efficient to only call fastGetAttribute and check for null instead.
> 
> It would be good at some point to research if the behavior here is correct. These are the two quirks I noticed:
> 
> - If a form attribute gives an ID that is used for an object other than a form that comes earlier in the document than the form, then we don’t associate the element with the form. Even if there is also a form with that ID.
> - Changes to the ID of the form or of an object other than the form that comes earlier in the document after the element is inserted into the tree have no effect.

* Removed the braces.
* Renamed: formElement -> newFormCandidate
* Merged the fastHasAttribute() call and the fastGetAttribute() call into one fastGetAttribute() call.

> - If a form attribute gives an ID that is used for an object other than a form that comes earlier in the document than the form, then we don’t associate the element with the form. Even if there is also a form with that ID.

The specification explicitly says that this is a correct behavior.

> - Changes to the ID of the form or of an object other than the form that comes earlier in the document after the element is inserted into the tree have no effect.

I think the current code works consistently in such case.

>> Source/WebCore/html/FormAssociatedElement.h:73
>> +    // subclass, you need to add setForm(0) to the destructor of the subclass.
> 
> Would be better to use the formal C++ term, “class derived from this one” or “derived class”, rather than “subclass”.
> 
> I’d say “If you add an override of willChangeForm() or didChangeForm() to a class derived from this one, you will need to add a call to setForm(0) to the destructor of that class".

I copied your sentence.
Comment 25 Kent Tamura 2012-01-10 20:32:07 PST
Comment on attachment 121792 [details]
Patch by tkent 5

View in context: https://bugs.webkit.org/attachment.cgi?id=121792&action=review

>> Source/WebCore/dom/CheckedRadioButtons.cpp:70
>> +        return;
> 
> This is not needed for correctness, so I suggest we leave it out.

I reverted this part.  I'll improve the performance later.
Comment 26 Kent Tamura 2012-01-10 21:03:38 PST
Committed r104668: <http://trac.webkit.org/changeset/104668>