Changeset 87980 in webkit


Ignore:
Timestamp:
Jun 2, 2011, 6:15:25 PM (14 years ago)
Author:
tkent@chromium.org
Message:

2011-06-02 Kent Tamura <tkent@chromium.org>

Reviewed by Dimitri Glazkov.

REGRESSION(r87014): Cloned text <input> doesn't work well.
https://bugs.webkit.org/show_bug.cgi?id=61909

  • fast/forms/textfield-clone-expected.txt: Added.
  • fast/forms/textfield-clone.html: Added.

2011-06-02 Kent Tamura <tkent@chromium.org>

Reviewed by Dimitri Glazkov.

REGRESSION(r87014): Cloned text <input> doesn't work well.
https://bugs.webkit.org/show_bug.cgi?id=61909

The default implementation of Element::cloneNode() creates a clone
node by Document::createElement(). So, if a customized class is used for
shadow nodes, cloneNode() doesn't create a node of the correct class.

Such custom classes need to override Element
cloneElementWithoutAttributesAndChildren().

TextFieldInputType and SearchInputType had references to shadow nodes
initialized in createShadowSubtree(). However createShadowSubtree() is
not called if the host node is cloned. The accessors for shadow nodes
should search a shadow tree.

Test: fast/forms/textfield-clone.html

  • html/SearchInputType.cpp: Remove data members for shadow nodes, and the accessors search the shadow tree for the requested node by TreeScope::getElementById(). (WebCore::SearchInputType::SearchInputType): (WebCore::innerBlockId): (WebCore::resultButtonId): (WebCore::cancelButtonId): (WebCore::SearchInputType::createShadowSubtree): (WebCore::SearchInputType::innerBlockElement): (WebCore::SearchInputType::resultsButtonElement): (WebCore::SearchInputType::cancelButtonElement):
  • html/SearchInputType.h:
  • html/TextFieldInputType.cpp: ditto. (WebCore::TextFieldInputType::TextFieldInputType): (WebCore::TextFieldInputType::innerTextId): (WebCore::spinButtonId): (WebCore::TextFieldInputType::speechButtonId): (WebCore::TextFieldInputType::appendChildAndSetId): (WebCore::TextFieldInputType::createShadowSubtree): (WebCore::TextFieldInputType::getShadowElementById): (WebCore::TextFieldInputType::innerTextElement): (WebCore::TextFieldInputType::innerSpinButtonElement): (WebCore::TextFieldInputType::speechButtonElement):
  • html/TextFieldInputType.h:
  • html/shadow/TextControlInnerElements.cpp: Overrides cloneElementWithoutAttributesAndChildren() in order that cloneNode() produces an instance of the correct class. (WebCore::TextControlInnerElement::cloneElementWithoutAttributesAndChildren): (WebCore::TextControlInnerTextElement::cloneElementWithoutAttributesAndChildren): (WebCore::SearchFieldResultsButtonElement::cloneElementWithoutAttributesAndChildren): (WebCore::SearchFieldCancelButtonElement::cloneElementWithoutAttributesAndChildren): (WebCore::SpinButtonElement::cloneElementWithoutAttributesAndChildren): (WebCore::InputFieldSpeechButtonElement::cloneElementWithoutAttributesAndChildren):
  • html/shadow/TextControlInnerElements.h:
Location:
trunk
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r87979 r87980  
     12011-06-02  Kent Tamura  <tkent@chromium.org>
     2
     3        Reviewed by Dimitri Glazkov.
     4
     5        REGRESSION(r87014): Cloned text <input> doesn't work well.
     6        https://bugs.webkit.org/show_bug.cgi?id=61909
     7
     8        * fast/forms/textfield-clone-expected.txt: Added.
     9        * fast/forms/textfield-clone.html: Added.
     10
    1112011-06-02  Adam Barth  <abarth@webkit.org>
    212
  • trunk/Source/WebCore/ChangeLog

    r87978 r87980  
     12011-06-02  Kent Tamura  <tkent@chromium.org>
     2
     3        Reviewed by Dimitri Glazkov.
     4
     5        REGRESSION(r87014): Cloned text <input> doesn't work well.
     6        https://bugs.webkit.org/show_bug.cgi?id=61909
     7
     8        The default implementation of Element::cloneNode() creates a clone
     9        node by Document::createElement(). So, if a customized class is used for
     10        shadow nodes, cloneNode() doesn't create a node of the correct class.
     11        Such custom classes need to override Element::
     12        cloneElementWithoutAttributesAndChildren().
     13
     14        TextFieldInputType and SearchInputType had references to shadow nodes
     15        initialized in createShadowSubtree(). However createShadowSubtree() is
     16        not called if the host node is cloned. The accessors for shadow nodes
     17        should search a shadow tree.
     18
     19        Test: fast/forms/textfield-clone.html
     20
     21        * html/SearchInputType.cpp:
     22          Remove data members for shadow nodes, and the accessors search the
     23          shadow tree for the requested node by TreeScope::getElementById().
     24        (WebCore::SearchInputType::SearchInputType):
     25        (WebCore::innerBlockId):
     26        (WebCore::resultButtonId):
     27        (WebCore::cancelButtonId):
     28        (WebCore::SearchInputType::createShadowSubtree):
     29        (WebCore::SearchInputType::innerBlockElement):
     30        (WebCore::SearchInputType::resultsButtonElement):
     31        (WebCore::SearchInputType::cancelButtonElement):
     32        * html/SearchInputType.h:
     33        * html/TextFieldInputType.cpp: ditto.
     34        (WebCore::TextFieldInputType::TextFieldInputType):
     35        (WebCore::TextFieldInputType::innerTextId):
     36        (WebCore::spinButtonId):
     37        (WebCore::TextFieldInputType::speechButtonId):
     38        (WebCore::TextFieldInputType::appendChildAndSetId):
     39        (WebCore::TextFieldInputType::createShadowSubtree):
     40        (WebCore::TextFieldInputType::getShadowElementById):
     41        (WebCore::TextFieldInputType::innerTextElement):
     42        (WebCore::TextFieldInputType::innerSpinButtonElement):
     43        (WebCore::TextFieldInputType::speechButtonElement):
     44        * html/TextFieldInputType.h:
     45        * html/shadow/TextControlInnerElements.cpp:
     46          Overrides cloneElementWithoutAttributesAndChildren() in order that cloneNode()
     47          produces an instance of the correct class.
     48        (WebCore::TextControlInnerElement::cloneElementWithoutAttributesAndChildren):
     49        (WebCore::TextControlInnerTextElement::cloneElementWithoutAttributesAndChildren):
     50        (WebCore::SearchFieldResultsButtonElement::cloneElementWithoutAttributesAndChildren):
     51        (WebCore::SearchFieldCancelButtonElement::cloneElementWithoutAttributesAndChildren):
     52        (WebCore::SpinButtonElement::cloneElementWithoutAttributesAndChildren):
     53        (WebCore::InputFieldSpeechButtonElement::cloneElementWithoutAttributesAndChildren):
     54        * html/shadow/TextControlInnerElements.h:
     55
    1562011-05-28  Martin Robinson  <mrobinson@igalia.com>
    257
  • trunk/Source/WebCore/html/SearchInputType.cpp

    r87067 r87980  
    4141inline SearchInputType::SearchInputType(HTMLInputElement* element)
    4242    : BaseTextInputType(element)
    43     , m_innerBlock(0)
    44     , m_resultsButton(0)
    45     , m_cancelButton(0)
    4643{
    4744}
     
    6764}
    6865
     66static const AtomicString& innerBlockId()
     67{
     68    DEFINE_STATIC_LOCAL(AtomicString, id, ("innerBlock"));
     69    return id;
     70}
     71
     72static const AtomicString& resultButtonId()
     73{
     74    DEFINE_STATIC_LOCAL(AtomicString, id, ("resultButton"));
     75    return id;
     76}
     77
     78static const AtomicString& cancelButtonId()
     79{
     80    DEFINE_STATIC_LOCAL(AtomicString, id, ("cancelButton"));
     81    return id;
     82}
     83
    6984void SearchInputType::createShadowSubtree()
    7085{
    71     ASSERT(!m_innerBlock);
    72     ASSERT(!innerTextElement());
    73     ASSERT(!m_resultsButton);
    74     ASSERT(!m_cancelButton);
    75 
    76     ExceptionCode ec = 0;
    7786    Document* document = element()->document();
    7887    RefPtr<HTMLElement> inner = TextControlInnerElement::create(document);
    79     m_innerBlock = inner.get();
    80     element()->ensureShadowRoot()->appendChild(inner.release(), ec);
     88    HTMLElement* innerBlock = inner.get();
     89    appendChildAndSetId(element()->ensureShadowRoot(), inner.release(), innerBlockId());
    8190
    8291#if ENABLE(INPUT_SPEECH)
    83     if (element()->isSpeechEnabled()) {
    84         RefPtr<HTMLElement> speech = InputFieldSpeechButtonElement::create(document);
    85         setSpeechButtonElement(speech.get());
    86         element()->ensureShadowRoot()->appendChild(speech.release(), ec);
    87     }
     92    if (element()->isSpeechEnabled())
     93        appendChildAndSetId(element()->ensureShadowRoot(), InputFieldSpeechButtonElement::create(document), speechButtonId());
    8894#endif
    8995
    90     RefPtr<HTMLElement> results = SearchFieldResultsButtonElement::create(document);
    91     m_resultsButton = results.get();
    92     m_innerBlock->appendChild(results.release(), ec);
    93 
    94     RefPtr<HTMLElement> innerText = TextControlInnerTextElement::create(document);
    95     setInnerTextElement(innerText.get());
    96     m_innerBlock->appendChild(innerText.release(), ec);
    97 
    98     RefPtr<HTMLElement> cancel = SearchFieldCancelButtonElement::create(element()->document());
    99     m_cancelButton = cancel.get();
    100     m_innerBlock->appendChild(cancel.release(), ec);
     96    appendChildAndSetId(innerBlock, SearchFieldResultsButtonElement::create(document), resultButtonId());
     97    appendChildAndSetId(innerBlock, TextControlInnerTextElement::create(document), innerTextId());
     98    appendChildAndSetId(innerBlock, SearchFieldCancelButtonElement::create(document), cancelButtonId());
    10199}
    102100
    103 void SearchInputType::destroyShadowSubtree()
     101HTMLElement* SearchInputType::innerBlockElement() const
    104102{
    105     TextFieldInputType::destroyShadowSubtree();
    106     m_innerBlock = 0;
    107     m_resultsButton = 0;
    108     m_cancelButton = 0;
     103    return getShadowElementById(innerBlockId());
    109104}
    110105
     106HTMLElement* SearchInputType::resultsButtonElement() const
     107{
     108    return getShadowElementById(resultButtonId());
     109}
     110
     111HTMLElement* SearchInputType::cancelButtonElement() const
     112{
     113    return getShadowElementById(cancelButtonId());
     114}
    111115
    112116} // namespace WebCore
  • trunk/Source/WebCore/html/SearchInputType.h

    r87067 r87980  
    3636namespace WebCore {
    3737
    38 class SearchFieldCancelButtonElement;
    39 class SearchFieldResultsButtonElement;
    40 
    4138class SearchInputType : public BaseTextInputType {
    4239public:
    4340    static PassOwnPtr<InputType> create(HTMLInputElement*);
    44 
    45 protected:
    46     virtual void createShadowSubtree();
    47     virtual void destroyShadowSubtree();
    4841
    4942private:
     
    5245    virtual bool shouldRespectSpeechAttribute();
    5346    virtual bool isSearchField() const;
    54     virtual HTMLElement* innerBlockElement() const { return m_innerBlock; }
    55     virtual HTMLElement* resultsButtonElement() const { return m_resultsButton; }
    56     virtual HTMLElement* cancelButtonElement() const { return m_cancelButton; }
    57 
    58     HTMLElement* m_innerBlock;
    59     HTMLElement* m_resultsButton;
    60     HTMLElement* m_cancelButton;
     47    virtual void createShadowSubtree();
     48    virtual HTMLElement* innerBlockElement() const;
     49    virtual HTMLElement* resultsButtonElement() const;
     50    virtual HTMLElement* cancelButtonElement() const;
    6151};
    6252
  • trunk/Source/WebCore/html/TextFieldInputType.cpp

    r87881 r87980  
    3636#include "Frame.h"
    3737#include "HTMLInputElement.h"
     38#include "HTMLNames.h"
    3839#include "KeyboardEvent.h"
    3940#include "RenderTextControlSingleLine.h"
     
    4849namespace WebCore {
    4950
     51using namespace HTMLNames;
     52
    5053TextFieldInputType::TextFieldInputType(HTMLInputElement* element)
    5154    : InputType(element)
    52     , m_innerText(0)
    53     , m_innerSpinButton(0)
    54 #if ENABLE(INPUT_SPEECH)
    55     , m_speechButton(0)
    56 #endif
    5755{
    5856}
     
    130128}
    131129
     130const AtomicString& TextFieldInputType::innerTextId() const
     131{
     132    DEFINE_STATIC_LOCAL(AtomicString, id, ("innerText"));
     133    return id;
     134}
     135
     136static const AtomicString& spinButtonId()
     137{
     138    DEFINE_STATIC_LOCAL(AtomicString, id, ("spinButton"));
     139    return id;
     140}
     141
     142#if ENABLE(INPUT_SPEECH)
     143const AtomicString& TextFieldInputType::speechButtonId() const
     144{
     145    DEFINE_STATIC_LOCAL(AtomicString, id, ("speechButton"));
     146    return id;
     147}
     148#endif
     149
     150void TextFieldInputType::appendChildAndSetId(ContainerNode* parent, PassRefPtr<HTMLElement> child, const AtomicString& id)
     151{
     152    ExceptionCode ec = 0;
     153    child->setAttribute(idAttr, id);
     154    parent->appendChild(child, ec);
     155}
     156
    132157void TextFieldInputType::createShadowSubtree()
    133158{
    134     ASSERT(!m_innerText);
    135     ASSERT(!m_innerSpinButton);
    136 
    137     bool shouldHaveSpinButton = RenderTheme::themeForPage(element()->document()->page())->shouldHaveSpinButton(element());
     159    Document* document = element()->document();
     160    bool shouldHaveSpinButton = RenderTheme::themeForPage(document->page())->shouldHaveSpinButton(element());
    138161    bool hasDecorations = shouldHaveSpinButton;
    139162#if ENABLE(INPUT_SPEECH)
     
    142165#endif
    143166
    144     ExceptionCode ec = 0;
    145     Document* document = element()->document();
    146     RefPtr<HTMLElement> innerText = TextControlInnerTextElement::create(document);
    147     m_innerText = innerText.get();
    148     element()->ensureShadowRoot()->appendChild(innerText.release(), ec);
     167    ShadowRoot* shadowRoot = element()->ensureShadowRoot();
     168    appendChildAndSetId(shadowRoot, TextControlInnerTextElement::create(document), innerTextId());
    149169    if (!hasDecorations)
    150170        return;
    151171
    152172#if ENABLE(INPUT_SPEECH)
    153     ASSERT(!m_speechButton);
    154     if (element()->isSpeechEnabled()) {
    155         RefPtr<HTMLElement> speech = InputFieldSpeechButtonElement::create(document);
    156         m_speechButton = speech.get();
    157         element()->ensureShadowRoot()->appendChild(speech.release(), ec);
    158     }
    159 #endif
    160 
    161     if (shouldHaveSpinButton) {
    162         RefPtr<HTMLElement> inner = SpinButtonElement::create(document);
    163         m_innerSpinButton = inner.get();
    164         element()->ensureShadowRoot()->appendChild(inner.release(), ec);
    165     }
    166 }
    167 
    168 void TextFieldInputType::destroyShadowSubtree()
    169 {
    170     InputType::destroyShadowSubtree();
    171     m_innerText = 0;
    172 #if ENABLE(INPUT_SPEECH)
    173     m_speechButton = 0;
    174 #endif
    175     m_innerSpinButton = 0;
    176 }
     173    if (element()->isSpeechEnabled())
     174        appendChildAndSetId(shadowRoot, InputFieldSpeechButtonElement::create(document), speechButtonId());
     175#endif
     176
     177    if (shouldHaveSpinButton)
     178        appendChildAndSetId(shadowRoot, SpinButtonElement::create(document), spinButtonId());
     179}
     180
     181HTMLElement* TextFieldInputType::getShadowElementById(const AtomicString& id) const
     182{
     183    if (!element()->shadowRoot())
     184        return 0;
     185    Element* shadow = element()->shadowRoot()->getElementById(id);
     186    return shadow ? static_cast<HTMLElement*>(shadow) : 0;
     187}
     188
     189HTMLElement* TextFieldInputType::innerTextElement() const
     190{
     191    return getShadowElementById(innerTextId());
     192}
     193
     194HTMLElement* TextFieldInputType::innerSpinButtonElement() const
     195{
     196    return getShadowElementById(spinButtonId());
     197}
     198
     199#if ENABLE(INPUT_SPEECH)
     200HTMLElement* TextFieldInputType::speechButtonElement() const
     201{
     202    return getShadowElementById(speechButtonId());
     203}
     204#endif
    177205
    178206bool TextFieldInputType::shouldUseInputMethod() const
  • trunk/Source/WebCore/html/TextFieldInputType.h

    r87881 r87980  
    3636namespace WebCore {
    3737
     38class ContainerNode;
     39
    3840// The class represents types of which UI contain text fields.
    3941// It supports not only the types for BaseTextInputType but also type=number.
     
    4648    void handleWheelEventForSpinButton(WheelEvent*);
    4749
    48     virtual HTMLElement* innerTextElement() const { return m_innerText; }
    49     virtual HTMLElement* innerSpinButtonElement() const { return m_innerSpinButton; }
     50    virtual HTMLElement* innerTextElement() const;
     51    virtual HTMLElement* innerSpinButtonElement() const;
    5052#if ENABLE(INPUT_SPEECH)
    51     virtual HTMLElement* speechButtonElement() const { return m_speechButton; }
     53    virtual HTMLElement* speechButtonElement() const;
    5254#endif
    5355
    5456protected:
     57    const AtomicString& innerTextId() const;
     58#if ENABLE(INPUT_SPEECH)
     59    const AtomicString& speechButtonId() const;
     60#endif
     61    static void appendChildAndSetId(ContainerNode*, PassRefPtr<HTMLElement>, const AtomicString&);
    5562    virtual void createShadowSubtree();
    56     virtual void destroyShadowSubtree();
    57     void setInnerTextElement(HTMLElement* element) { m_innerText = element; }
    58 #if ENABLE(INPUT_SPEECH)
    59     void setSpeechButtonElement(HTMLElement* element) { m_speechButton = element; }
    60 #endif
     63    HTMLElement* getShadowElementById(const AtomicString&) const;
    6164
    6265private:
     
    7073    virtual String sanitizeValue(const String&);
    7174    virtual bool shouldRespectListAttribute();
    72 
    73     HTMLElement* m_innerText;
    74     HTMLElement* m_innerSpinButton;
    75 #if ENABLE(INPUT_SPEECH)
    76     HTMLElement* m_speechButton;
    77 #endif
    7875};
    7976
  • trunk/Source/WebCore/html/shadow/TextControlInnerElements.cpp

    r87881 r87980  
    6464}
    6565
     66PassRefPtr<Element> TextControlInnerElement::cloneElementWithoutAttributesAndChildren() const
     67{
     68    return create(document());
     69}
     70
    6671// ----------------------------
    6772
     
    108113    RenderTextControl* parentRenderer = toRenderTextControl(shadowAncestorNode()->renderer());
    109114    return parentRenderer->createInnerTextStyle(parentRenderer->style());
     115}
     116
     117PassRefPtr<Element> TextControlInnerTextElement::cloneElementWithoutAttributesAndChildren() const
     118{
     119    return create(document());
    110120}
    111121
     
    159169}
    160170
     171PassRefPtr<Element> SearchFieldResultsButtonElement::cloneElementWithoutAttributesAndChildren() const
     172{
     173    return create(document());
     174}
     175
    161176// ----------------------------
    162177
     
    220235    if (!event->defaultHandled())
    221236        HTMLDivElement::defaultEventHandler(event);
     237}
     238
     239PassRefPtr<Element> SearchFieldCancelButtonElement::cloneElementWithoutAttributesAndChildren() const
     240{
     241    return create(document());
    222242}
    223243
     
    358378}
    359379
     380PassRefPtr<Element> SpinButtonElement::cloneElementWithoutAttributesAndChildren() const
     381{
     382    return create(document());
     383}
    360384
    361385// ----------------------------
     
    526550}
    527551
     552PassRefPtr<Element> InputFieldSpeechButtonElement::cloneElementWithoutAttributesAndChildren() const
     553{
     554    return create(document());
     555}
     556
    528557#endif // ENABLE(INPUT_SPEECH)
    529558
  • trunk/Source/WebCore/html/shadow/TextControlInnerElements.h

    r87881 r87980  
    4747private:
    4848    virtual bool isMouseFocusable() const { return false; }
     49    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
    4950};
    5051
     
    6061    virtual PassRefPtr<RenderStyle> styleForRenderer();
    6162    virtual bool isMouseFocusable() const { return false; }
     63    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
    6264};
    6365
     
    7274    virtual const AtomicString& shadowPseudoId() const;
    7375    virtual bool isMouseFocusable() const { return false; }
     76    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
    7477};
    7578
     
    8588    virtual void detach();
    8689    virtual bool isMouseFocusable() const { return false; }
     90    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
    8791
    8892    bool m_capturing;
     
    114118    virtual void setHovered(bool = true);
    115119    virtual bool isMouseFocusable() const { return false; }
     120    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
    116121
    117122    bool m_capturing;
     
    153158    virtual bool isMouseFocusable() const { return false; }
    154159    virtual void attach();
     160    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
    155161
    156162    bool m_capturing;
Note: See TracChangeset for help on using the changeset viewer.