Reviewed by George Staikos.
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Jan 2009 22:29:09 +0000 (22:29 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Jan 2009 22:29:09 +0000 (22:29 +0000)
Fixes: https://bugs.webkit.org/show_bug.cgi?id=23434

Add WML <input> element support - it required a lot of changes to the RenderText*/HTMLInput* code.
Now any language can provide <input>-style elements, without having to inherit from HTML* classes.

No WML specific features/attributes are handled so far. A follow-up patch will provide those bits.
Added very simple fast/wml/input.wml, just checking that input elements can be rendered properly now.
Detailed testcases will follow in conjunction with the WML specific attribute support.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@40071 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/wml/input.wml [new file with mode: 0644]
LayoutTests/platform/mac/fast/wml/input-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/wml/input-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/wml/input-expected.txt [new file with mode: 0644]
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.pro
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/css/CSSStyleSelector.cpp
WebCore/dom/FormControlElement.cpp
WebCore/dom/InputElement.cpp
WebCore/wml/WMLInputElement.cpp [new file with mode: 0644]
WebCore/wml/WMLInputElement.h [new file with mode: 0644]
WebCore/wml/WMLTagNames.in
WebKit/mac/ChangeLog
WebKit/mac/WebCoreSupport/WebEditorClient.mm

index 34c8aa4..27a356e 100644 (file)
@@ -1,3 +1,16 @@
+2009-01-20  Nikolas Zimmermann  <nikolas.zimmermann@torchmobile.com>
+
+        Reviewed by George Staikos.
+
+        Fixes: https://bugs.webkit.org/show_bug.cgi?id=23434
+
+        Add minimal WML input element testcase: fast/wml/input.wml
+
+        * fast/wml/input.wml: Added.
+        * platform/mac/fast/wml/input-expected.checksum: Added.
+        * platform/mac/fast/wml/input-expected.png: Added.
+        * platform/mac/fast/wml/input-expected.txt: Added.
+
 2009-01-20  Pierre-Olivier Latour  <pol@apple.com>
 
         Previously uploaded reference images were generated with Perian installed, which affected them
diff --git a/LayoutTests/fast/wml/input.wml b/LayoutTests/fast/wml/input.wml
new file mode 100644 (file)
index 0000000..3fd0a62
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
+<wml>
+<card>
+<p>Very simple test, checking that input elements are rendered correctly</p>
+<input type="text" value="Test"/>
+<input type="password" value="Password"/>
+</card>
+</wml>
diff --git a/LayoutTests/platform/mac/fast/wml/input-expected.checksum b/LayoutTests/platform/mac/fast/wml/input-expected.checksum
new file mode 100644 (file)
index 0000000..e768b69
--- /dev/null
@@ -0,0 +1 @@
+bd3f39170d9ce9d2e331779514699da8
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/wml/input-expected.png b/LayoutTests/platform/mac/fast/wml/input-expected.png
new file mode 100644 (file)
index 0000000..30c4fbf
Binary files /dev/null and b/LayoutTests/platform/mac/fast/wml/input-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/wml/input-expected.txt b/LayoutTests/platform/mac/fast/wml/input-expected.txt
new file mode 100644 (file)
index 0000000..b1cf0f9
--- /dev/null
@@ -0,0 +1,22 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x77
+  RenderBlock {wml} at (0,0) size 800x77
+    RenderBlock {card} at (8,16) size 784x53
+      RenderBlock {p} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 430x18
+          text run at (0,0) width 430: "Very simple test, checking that input elements are rendered correctly"
+      RenderBlock (anonymous) at (0,34) size 784x19
+        RenderTextControl {input} at (0,0) size 148x19 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
+        RenderText {#text} at (148,0) size 4x18
+          text run at (148,0) width 4: " "
+        RenderTextControl {input} at (152,0) size 148x19 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
+        RenderText {#text} at (0,0) size 0x0
+layer at (11,53) size 142x13
+  RenderBlock {div} at (3,3) size 142x13
+    RenderText {#text} at (1,0) size 23x13
+      text run at (1,0) width 23: "Test"
+layer at (163,53) size 142x13
+  RenderBlock {div} at (3,3) size 142x13
+    RenderText {#text} at (1,0) size 50x13
+      text run at (1,0) width 50: "\x{2022}\x{2022}\x{2022}\x{2022}\x{2022}\x{2022}\x{2022}\x{2022}"
index 0474dae..f505b5a 100644 (file)
@@ -1,3 +1,75 @@
+2009-01-20  Nikolas Zimmermann  <nikolas.zimmermann@torchmobile.com>
+
+        Reviewed by George Staikos.
+
+        Fixes: https://bugs.webkit.org/show_bug.cgi?id=23434
+
+        Add WML <input> element support - it required a lot of changes to the RenderText*/HTMLInput* code.
+        Now any language can provide <input>-style elements, without having to inherit from HTML* classes.
+
+        No WML specific features/attributes are handled so far. A follow-up patch will provide those bits.
+        Added very simple fast/wml/input.wml, just checking that input elements can be rendered properly now.
+        Detailed testcases will follow in conjunction with the WML specific attribute support.
+
+        * GNUmakefile.am:
+        * WebCore.pro:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::adjustRenderStyle):
+        * dom/FormControlElement.cpp: Activate disabled code from previous checking.
+        (WebCore::formControlElementForElement):
+        * dom/InputElement.cpp: Ditto.
+        (WebCore::inputElementForElement):
+        * wml/WMLInputElement.cpp: Added.
+        (WebCore::WMLInputElement::WMLInputElement):
+        (WebCore::WMLInputElement::~WMLInputElement):
+        (WebCore::isInputFocusable):
+        (WebCore::WMLInputElement::isKeyboardFocusable):
+        (WebCore::WMLInputElement::isMouseFocusable):
+        (WebCore::WMLInputElement::dispatchFocusEvent):
+        (WebCore::WMLInputElement::dispatchBlurEvent):
+        (WebCore::WMLInputElement::updateFocusAppearance):
+        (WebCore::WMLInputElement::aboutToUnload):
+        (WebCore::WMLInputElement::size):
+        (WebCore::WMLInputElement::name):
+        (WebCore::WMLInputElement::value):
+        (WebCore::WMLInputElement::setValue):
+        (WebCore::WMLInputElement::setValueFromRenderer):
+        (WebCore::WMLInputElement::saveState):
+        (WebCore::WMLInputElement::restoreState):
+        (WebCore::WMLInputElement::select):
+        (WebCore::WMLInputElement::accessKeyAction):
+        (WebCore::WMLInputElement::parseMappedAttribute):
+        (WebCore::WMLInputElement::copyNonAttributeProperties):
+        (WebCore::WMLInputElement::createRenderer):
+        (WebCore::WMLInputElement::attach):
+        (WebCore::WMLInputElement::detach):
+        (WebCore::WMLInputElement::appendFormData):
+        (WebCore::WMLInputElement::reset):
+        (WebCore::WMLInputElement::defaultEventHandler):
+        (WebCore::WMLInputElement::cacheSelection):
+        (WebCore::WMLInputElement::constrainValue):
+        (WebCore::WMLInputElement::documentDidBecomeActive):
+        (WebCore::WMLInputElement::placeholderShouldBeVisible):
+        (WebCore::WMLInputElement::willMoveToNewOwnerDocument):
+        (WebCore::WMLInputElement::didMoveToNewOwnerDocument):
+        * wml/WMLInputElement.h: Added.
+        (WebCore::WMLInputElement::valueMatchesRenderer):
+        (WebCore::WMLInputElement::setValueMatchesRenderer):
+        (WebCore::WMLInputElement::shouldUseInputMethod):
+        (WebCore::WMLInputElement::isChecked):
+        (WebCore::WMLInputElement::isIndeterminate):
+        (WebCore::WMLInputElement::isTextControl):
+        (WebCore::WMLInputElement::isRadioButton):
+        (WebCore::WMLInputElement::isTextField):
+        (WebCore::WMLInputElement::isSearchField):
+        (WebCore::WMLInputElement::isInputTypeHidden):
+        (WebCore::WMLInputElement::isPasswordField):
+        (WebCore::WMLInputElement::searchEventsShouldBeDispatched):
+        (WebCore::WMLInputElement::placeholderValue):
+        * wml/WMLTagNames.in:
+
 2009-01-20  Darin Adler  <darin@apple.com>
 
         Reviewed by John Sullivan.
index 9b98807..787c4a4 100644 (file)
@@ -2213,6 +2213,7 @@ webcore_sources += \
        WebCore/wml/WMLGoElement.cpp \
        WebCore/wml/WMLImageElement.cpp \
        WebCore/wml/WMLImageLoader.cpp \
+       WebCore/wml/WMLInputElement.cpp \
        WebCore/wml/WMLInsertedLegendElement.cpp \
        WebCore/wml/WMLIntrinsicEvent.cpp \
        WebCore/wml/WMLIntrinsicEventHandler.cpp \
index 2c276a4..8d6306e 100644 (file)
@@ -1416,6 +1416,7 @@ contains(DEFINES, ENABLE_WML=1) {
         wml/WMLGoElement.cpp \
         wml/WMLImageElement.cpp \
         wml/WMLImageLoader.cpp \
+        wml/WMLInputElement.cpp \
         wml/WMLInsertedLegendElement.cpp \
         wml/WMLIntrinsicEvent.cpp \
         wml/WMLIntrinsicEventHandler.cpp \
index a8a763d..c14d058 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\wml\WMLInputElement.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\wml\WMLInputElement.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\wml\WMLInsertedLegendElement.cpp"\r
                                >\r
                        </File>\r
index d81ccb0..b6bf885 100644 (file)
@@ -80,6 +80,8 @@
                08807B810ED709AB003F6975 /* WMLSetvarElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 08807B750ED709AB003F6975 /* WMLSetvarElement.h */; };
                08820BDE0EF5D381009099A8 /* WMLTableElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08820BDC0EF5D381009099A8 /* WMLTableElement.cpp */; };
                08820BDF0EF5D381009099A8 /* WMLTableElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 08820BDD0EF5D381009099A8 /* WMLTableElement.h */; };
+               088451150F267B63007F139E /* WMLInputElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 088451130F267B62007F139E /* WMLInputElement.cpp */; };
+               088451160F267B63007F139E /* WMLInputElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 088451140F267B63007F139E /* WMLInputElement.h */; };
                088C97120ECB6D92000534BA /* WMLNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3AB490E556F2400E9C0C0 /* WMLNames.cpp */; };
                088C97130ECB6D9D000534BA /* WMLNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CA3AB480E556F2400E9C0C0 /* WMLNames.h */; };
                088C97510ECB6E28000534BA /* WMLAElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6B99180E52E37300487BB7 /* WMLAElement.cpp */; };
                08807B750ED709AB003F6975 /* WMLSetvarElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLSetvarElement.h; sourceTree = "<group>"; };
                08820BDC0EF5D381009099A8 /* WMLTableElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLTableElement.cpp; sourceTree = "<group>"; };
                08820BDD0EF5D381009099A8 /* WMLTableElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLTableElement.h; sourceTree = "<group>"; };
+               088451130F267B62007F139E /* WMLInputElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLInputElement.cpp; sourceTree = "<group>"; };
+               088451140F267B63007F139E /* WMLInputElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLInputElement.h; sourceTree = "<group>"; };
                0893E4650ECB68F400A28563 /* WMLPageState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLPageState.cpp; sourceTree = "<group>"; };
                0893E4660ECB68F400A28563 /* WMLPageState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLPageState.h; sourceTree = "<group>"; };
                089582530E857A7E00F82C83 /* ImageLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageLoader.cpp; sourceTree = "<group>"; };
                                08C4C5150EF19A4000E4840F /* WMLImageElement.h */,
                                08C4C5160EF19A4000E4840F /* WMLImageLoader.cpp */,
                                08C4C5170EF19A4000E4840F /* WMLImageLoader.h */,
+                               088451130F267B62007F139E /* WMLInputElement.cpp */,
+                               088451140F267B63007F139E /* WMLInputElement.h */,
                                087FFA0D0EFF3ED3009DBD88 /* WMLInsertedLegendElement.cpp */,
                                087FFA0E0EFF3ED3009DBD88 /* WMLInsertedLegendElement.h */,
                                080AEC7D0ED8708A00DF4CCE /* WMLIntrinsicEvent.cpp */,
                                08807B770ED709AB003F6975 /* WMLGoElement.h in Headers */,
                                08C4C5190EF19A4000E4840F /* WMLImageElement.h in Headers */,
                                08C4C51B0EF19A4000E4840F /* WMLImageLoader.h in Headers */,
+                               088451160F267B63007F139E /* WMLInputElement.h in Headers */,
                                087FFA100EFF3ED3009DBD88 /* WMLInsertedLegendElement.h in Headers */,
                                080AEC820ED8708B00DF4CCE /* WMLIntrinsicEvent.h in Headers */,
                                080AEC840ED8708B00DF4CCE /* WMLIntrinsicEventHandler.h in Headers */,
                                08807B760ED709AB003F6975 /* WMLGoElement.cpp in Sources */,
                                08C4C5180EF19A4000E4840F /* WMLImageElement.cpp in Sources */,
                                08C4C51A0EF19A4000E4840F /* WMLImageLoader.cpp in Sources */,
+                               088451150F267B63007F139E /* WMLInputElement.cpp in Sources */,
                                087FFA0F0EFF3ED3009DBD88 /* WMLInsertedLegendElement.cpp in Sources */,
                                080AEC810ED8708B00DF4CCE /* WMLIntrinsicEvent.cpp in Sources */,
                                080AEC830ED8708B00DF4CCE /* WMLIntrinsicEventHandler.cpp in Sources */,
index 356b355..013cd96 100644 (file)
@@ -1474,6 +1474,7 @@ void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, Element *e)
               e->hasTagName(selectTag) || e->hasTagName(textareaTag)
 #if ENABLE(WML)
               || e->hasTagName(WMLNames::insertedLegendTag)
+              || e->hasTagName(WMLNames::inputTag)
 #endif
        )) {
         if (style->width().isAuto())
index c392f5f..c278bae 100644 (file)
@@ -39,8 +39,7 @@ FormControlElement* formControlElementForElement(Element* element)
             return static_cast<HTMLFormControlElement*>(element);
     }
 
-    // FIXME: Enable this code, once the follow-up WMLInputElement addition patch lands.
-#if ENABLE(WML) && 0
+#if ENABLE(WML)
     if (element->isWMLElement() && element->hasTagName(WMLNames::inputTag))
         return static_cast<WMLInputElement*>(element);
 #endif
index 7c080c6..d4019ab 100644 (file)
@@ -296,8 +296,7 @@ InputElement* inputElementForElement(Element* element)
     if (element->isHTMLElement() && (element->hasTagName(inputTag) || element->hasTagName(isindexTag)))
         return static_cast<HTMLInputElement*>(element);
 
-    // FIXME: Enable this code, once the follow-up WMLInputElement addition patch lands.
-#if ENABLE(WML) && 0
+#if ENABLE(WML)
     if (element->isWMLElement() && element->hasTagName(WMLNames::inputTag))
         return static_cast<WMLInputElement*>(element);
 #endif
diff --git a/WebCore/wml/WMLInputElement.cpp b/WebCore/wml/WMLInputElement.cpp
new file mode 100644 (file)
index 0000000..dc39bf8
--- /dev/null
@@ -0,0 +1,332 @@
+/**
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(WML)
+#include "WMLInputElement.h"
+
+#include "Document.h"
+#include "EventNames.h"
+#include "FormDataList.h"
+#include "Frame.h"
+#include "HTMLNames.h"
+#include "KeyboardEvent.h"
+#include "RenderTextControlSingleLine.h"
+#include "TextEvent.h"
+
+namespace WebCore {
+
+WMLInputElement::WMLInputElement(const QualifiedName& tagName, Document* doc)
+    : WMLElement(tagName, doc)
+    , m_data(this, this)
+    , m_isPasswordField(false)
+    , m_valueMatchesRenderer(false)
+{
+}
+
+WMLInputElement::~WMLInputElement()
+{
+    if (m_isPasswordField)
+        document()->unregisterForDocumentActivationCallbacks(this);
+}
+
+static inline bool isInputFocusable(RenderObject* renderer)
+{
+    if (!renderer)
+        return false;
+
+    if (!renderer->width() || !renderer->height())
+        return false;
+
+    if (RenderStyle* style = renderer->style()) {
+        if (style->visibility() != VISIBLE)
+            return false;
+    }
+
+    return true;
+}
+
+bool WMLInputElement::isKeyboardFocusable(KeyboardEvent*) const
+{
+    return isInputFocusable(renderer());
+}
+
+bool WMLInputElement::isMouseFocusable() const
+{
+    return isInputFocusable(renderer());
+}
+
+void WMLInputElement::dispatchFocusEvent()
+{
+    InputElement::dispatchFocusEvent(m_data, document());
+    WMLElement::dispatchFocusEvent();
+}
+
+void WMLInputElement::dispatchBlurEvent()
+{
+    InputElement::dispatchBlurEvent(m_data, document());
+    WMLElement::dispatchBlurEvent();
+}
+
+void WMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
+{
+    InputElement::updateFocusAppearance(m_data, document(), restorePreviousSelection);
+}
+
+void WMLInputElement::aboutToUnload()
+{
+    InputElement::aboutToUnload(m_data, document());
+}
+
+int WMLInputElement::size() const
+{
+    return m_data.size();
+}
+
+const AtomicString& WMLInputElement::name() const
+{
+    return m_data.name();
+}
+
+String WMLInputElement::value() const
+{
+    String value = m_data.value();
+    if (value.isNull())
+        value = constrainValue(getAttribute(HTMLNames::valueAttr));
+
+    return value;
+}
+
+void WMLInputElement::setValue(const String& value)
+{
+    InputElement::updatePlaceholderVisibility(m_data, document());
+    setValueMatchesRenderer(false);
+    m_data.setValue(constrainValue(value));
+    if (inDocument())
+        document()->updateRendering();
+    if (renderer())
+        renderer()->updateFromElement();
+    setChanged();
+
+    unsigned max = m_data.value().length();
+    if (document()->focusedNode() == this)
+        InputElement::updateSelectionRange(m_data, max, max);
+    else
+        cacheSelection(max, max);
+
+    InputElement::notifyFormStateChanged(m_data, document());
+}
+
+void WMLInputElement::setValueFromRenderer(const String& value)
+{
+    InputElement::setValueFromRenderer(m_data, document(), value);
+}
+
+bool WMLInputElement::saveState(String& result) const
+{
+    if (m_isPasswordField)
+        return false;
+
+    result = value();
+    return true;
+}
+
+void WMLInputElement::restoreState(const String& state)
+{
+    ASSERT(!m_isPasswordField); // should never save/restore password fields
+    setValue(state);
+}
+
+void WMLInputElement::select()
+{
+    if (RenderTextControl* r = static_cast<RenderTextControl*>(renderer()))
+        r->select();
+}
+
+void WMLInputElement::accessKeyAction(bool)
+{
+    // should never restore previous selection here
+    focus(false);
+}
+
+void WMLInputElement::parseMappedAttribute(MappedAttribute* attr)
+{
+    if (attr->name() == HTMLNames::nameAttr)
+        m_data.setName(parseValueForbiddingVariableReferences(attr->value()));
+    else if (attr->name() == HTMLNames::typeAttr) {
+        String type = parseValueForbiddingVariableReferences(attr->value());
+        m_isPasswordField = (type == "password");
+    } else if (attr->name() == HTMLNames::valueAttr) {
+        // We only need to setChanged if the form is looking at the default value right now.
+        if (m_data.value().isNull())
+            setChanged();
+        setValueMatchesRenderer(false);
+    } else if (attr->name() == HTMLNames::maxlengthAttr)
+        InputElement::parseMaxLengthAttribute(m_data, attr);
+    else if (attr->name() == HTMLNames::sizeAttr)
+        InputElement::parseSizeAttribute(m_data, attr);
+    else
+        WMLElement::parseMappedAttribute(attr);
+
+    // FIXME: Handle 'accesskey' attribute
+    // FIXME: Handle 'format' attribute
+    // FIXME: Handle 'emptyok' attribute
+    // FIXME: Handle 'tabindex' attribute
+    // FIXME: Handle 'title' attribute
+}
+
+void WMLInputElement::copyNonAttributeProperties(const Element* source)
+{
+    const WMLInputElement* sourceElement = static_cast<const WMLInputElement*>(source);
+    m_data.setValue(sourceElement->m_data.value());
+    WMLElement::copyNonAttributeProperties(source);
+}
+
+RenderObject* WMLInputElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderTextControlSingleLine(this);
+}
+
+void WMLInputElement::attach()
+{
+    ASSERT(!attached());
+    WMLElement::attach();
+
+    // The call to updateFromElement() needs to go after the call through
+    // to the base class's attach() because that can sometimes do a close
+    // on the renderer.
+    if (renderer())
+        renderer()->updateFromElement();
+}  
+
+void WMLInputElement::detach()
+{
+    WMLElement::detach();
+    setValueMatchesRenderer(false);
+}
+    
+bool WMLInputElement::appendFormData(FormDataList& encoding, bool)
+{
+    if (name().isEmpty())
+        return false;
+
+    encoding.appendData(name(), value());
+    return true;
+}
+
+void WMLInputElement::reset()
+{
+    setValue(String());
+}
+
+void WMLInputElement::defaultEventHandler(Event* evt)
+{
+    bool clickDefaultFormButton = false;
+
+    if (evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n")
+        clickDefaultFormButton = true;
+
+    if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent() && focused() && document()->frame()
+        && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
+        evt->setDefaultHandled();
+        return;
+    }
+    
+    // Let the key handling done in EventTargetNode take precedence over the event handling here for editable text fields
+    if (!clickDefaultFormButton) {
+        WMLElement::defaultEventHandler(evt);
+        if (evt->defaultHandled())
+            return;
+    }
+
+    // Use key press event here since sending simulated mouse events
+    // on key down blocks the proper sending of the key press event.
+    if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) {
+        // Simulate mouse click on the default form button for enter for these types of elements.
+        if (static_cast<KeyboardEvent*>(evt)->charCode() == '\r')
+            clickDefaultFormButton = true;
+    }
+
+    if (clickDefaultFormButton) {
+        // Fire onChange for text fields.
+        RenderObject* r = renderer();
+        if (r && r->isEdited()) {
+            dispatchEventForType(eventNames().changeEvent, true, false);
+            
+            // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it.
+            r = renderer();
+            if (r)
+                r->setEdited(false);
+        }
+
+        evt->setDefaultHandled();
+        return;
+    }
+
+    if (evt->isBeforeTextInsertedEvent())
+        InputElement::handleBeforeTextInsertedEvent(m_data, document(), evt);
+
+    if (renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
+        static_cast<RenderTextControlSingleLine*>(renderer())->forwardEvent(evt);
+}
+
+void WMLInputElement::cacheSelection(int start, int end)
+{
+    m_data.setCachedSelectionStart(start);
+    m_data.setCachedSelectionEnd(end);
+}
+
+String WMLInputElement::constrainValue(const String& proposedValue) const
+{
+    return InputElement::constrainValue(m_data, proposedValue, m_data.maxLength());
+}
+
+void WMLInputElement::documentDidBecomeActive()
+{
+    ASSERT(m_isPasswordField);
+    reset();
+}
+
+bool WMLInputElement::placeholderShouldBeVisible() const
+{
+    return m_data.placeholderShouldBeVisible();
+}
+
+void WMLInputElement::willMoveToNewOwnerDocument()
+{
+    // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered
+    if (m_isPasswordField)
+        document()->unregisterForDocumentActivationCallbacks(this);
+
+    WMLElement::willMoveToNewOwnerDocument();
+}
+
+void WMLInputElement::didMoveToNewOwnerDocument()
+{
+    if (m_isPasswordField)
+        document()->registerForDocumentActivationCallbacks(this);
+
+    WMLElement::didMoveToNewOwnerDocument();
+}
+
+}
+
+#endif
diff --git a/WebCore/wml/WMLInputElement.h b/WebCore/wml/WMLInputElement.h
new file mode 100644 (file)
index 0000000..261101e
--- /dev/null
@@ -0,0 +1,101 @@
+/**
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WMLInputElement_h
+#define WMLInputElement_h
+
+#if ENABLE(WML)
+#include "FormControlElement.h"
+#include "InputElement.h"
+#include "WMLElement.h"
+
+namespace WebCore {
+
+class FormDataList;
+
+class WMLInputElement : public WMLElement, public FormControlElement, public InputElement {
+public:
+    WMLInputElement(const QualifiedName& tagName, Document*);
+    virtual ~WMLInputElement();
+
+    virtual bool valueMatchesRenderer() const { return m_valueMatchesRenderer; }
+    virtual void setValueMatchesRenderer(bool b = true) { m_valueMatchesRenderer = b; }
+
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isMouseFocusable() const;
+    virtual void dispatchFocusEvent();
+    virtual void dispatchBlurEvent();
+    virtual void updateFocusAppearance(bool restorePreviousSelection);
+    virtual void aboutToUnload();
+
+    virtual bool shouldUseInputMethod() const { return !m_isPasswordField; }
+    virtual bool isChecked() const { return false; }
+    virtual bool isIndeterminate() const { return false; }
+    virtual bool isTextControl() const { return true; }
+    virtual bool isRadioButton() const { return false; }
+    virtual bool isTextField() const { return true; }
+    virtual bool isSearchField() const { return false; }
+    virtual bool isInputTypeHidden() const { return false; }
+    virtual bool isPasswordField() const { return m_isPasswordField; }
+    virtual bool searchEventsShouldBeDispatched() const { return false; }
+
+    virtual int size() const;
+    virtual const AtomicString& name() const;
+    virtual String value() const;
+    virtual void setValue(const String&);
+    virtual String placeholderValue() const { return String(); }
+    virtual void setValueFromRenderer(const String&);
+
+    virtual bool saveState(String& value) const;
+    virtual void restoreState(const String&);
+
+    virtual void select();
+    virtual void accessKeyAction(bool sendToAnyElement);
+    virtual void parseMappedAttribute(MappedAttribute*);
+
+    virtual void copyNonAttributeProperties(const Element* source);
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual void attach();
+    virtual void detach();
+    virtual bool appendFormData(FormDataList&, bool);
+    virtual void reset();
+
+    virtual void defaultEventHandler(Event*);
+    virtual void cacheSelection(int start, int end);
+
+    virtual String constrainValue(const String& proposedValue) const;
+
+    virtual void documentDidBecomeActive();
+    virtual bool placeholderShouldBeVisible() const;
+
+    virtual void willMoveToNewOwnerDocument();
+    virtual void didMoveToNewOwnerDocument();
+
+private:
+    InputElementData m_data;
+    bool m_isPasswordField;
+    bool m_valueMatchesRenderer;
+};
+
+}
+
+#endif
+#endif
index 293c603..57e7b51 100644 (file)
@@ -12,6 +12,7 @@ fieldset interfaceName=WMLFieldSetElement
 go
 head interfaceName=WMLElement
 img interfaceName=WMLImageElement
+input
 # Note: 'insertedLegend' is not an official WML element - internal purpose only!
 insertedLegend interfaceName=WMLInsertedLegendElement
 meta
@@ -30,5 +31,5 @@ tr interfaceName=WMLElement
 
 #if 0
 # These elements have a corresponding HTML*Element class, that we want to share code with.
-# input, optgroup, option, select
+# optgroup, option, select
 #endif
index aea1055..e000851 100644 (file)
@@ -1,3 +1,20 @@
+2009-01-20  Nikolas Zimmermann  <nikolas.zimmermann@torchmobile.com>
+
+        Reviewed by George Staikos.
+
+        Fixes: https://bugs.webkit.org/show_bug.cgi?id=23434 (Add WML <input> element support)
+
+        Protect text field related WebEditorClient.mm methods against non-HTMLElement callers.
+        WebEditorClient.mm relies on HTMLInputElement as input element. Ignore calls from non-HTMLElement elements.
+
+        * WebCoreSupport/WebEditorClient.mm:
+        (WebEditorClient::textFieldDidBeginEditing):
+        (WebEditorClient::textFieldDidEndEditing):
+        (WebEditorClient::textDidChangeInTextField):
+        (WebEditorClient::doTextFieldCommandFromEvent):
+        (WebEditorClient::textWillBeDeletedInTextField):
+        (WebEditorClient::textDidChangeInTextArea):
+
 2009-01-19  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Sam Weinig.
index 6b51e0e..67d3cc2 100644 (file)
@@ -454,6 +454,9 @@ void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
 
 void WebEditorClient::textFieldDidBeginEditing(Element* element)
 {
+    if (!element->isHTMLElement())
+        return;
+
     DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element];
     FormDelegateLog(inputElement);
     CallFormDelegate(m_webView, @selector(textFieldDidBeginEditing:inFrame:), inputElement, kit(element->document()->frame()));
@@ -461,6 +464,9 @@ void WebEditorClient::textFieldDidBeginEditing(Element* element)
 
 void WebEditorClient::textFieldDidEndEditing(Element* element)
 {
+    if (!element->isHTMLElement())
+        return;
+
     DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element];
     FormDelegateLog(inputElement);
     CallFormDelegate(m_webView, @selector(textFieldDidEndEditing:inFrame:), inputElement, kit(element->document()->frame()));
@@ -468,6 +474,9 @@ void WebEditorClient::textFieldDidEndEditing(Element* element)
     
 void WebEditorClient::textDidChangeInTextField(Element* element)
 {
+    if (!element->isHTMLElement())
+        return;
+
     DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element];
     FormDelegateLog(inputElement);
     CallFormDelegate(m_webView, @selector(textDidChangeInTextField:inFrame:), inputElement, kit(element->document()->frame()));
@@ -498,6 +507,9 @@ static SEL selectorForKeyEvent(KeyboardEvent* event)
 
 bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event)
 {
+    if (!element->isHTMLElement())
+        return NO;
+
     DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element];
     FormDelegateLog(inputElement);
     if (SEL commandSelector = selectorForKeyEvent(event))
@@ -507,6 +519,9 @@ bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEven
 
 void WebEditorClient::textWillBeDeletedInTextField(Element* element)
 {
+    if (!element->isHTMLElement())
+        return;
+
     DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element];
     FormDelegateLog(inputElement);
     // We're using the deleteBackward selector for all deletion operations since the autofill code treats all deletions the same way.
@@ -515,6 +530,9 @@ void WebEditorClient::textWillBeDeletedInTextField(Element* element)
 
 void WebEditorClient::textDidChangeInTextArea(Element* element)
 {
+    if (!element->isHTMLElement())
+        return;
+
     DOMHTMLTextAreaElement* textAreaElement = [DOMHTMLTextAreaElement _wrapHTMLTextAreaElement:(HTMLTextAreaElement*)element];
     FormDelegateLog(textAreaElement);
     CallFormDelegate(m_webView, @selector(textDidChangeInTextArea:inFrame:), textAreaElement, kit(element->document()->frame()));