Expose a way to know when forms are added to a page or when form controls are added...
authorjberlin@webkit.org <jberlin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 May 2013 13:44:46 +0000 (13:44 +0000)
committerjberlin@webkit.org <jberlin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 May 2013 13:44:46 +0000 (13:44 +0000)
in the injected bundle
https://bugs.webkit.org/show_bug.cgi?id=116334

Reviewed by Alexey Proskuryakov.

Source/WebKit2:

Add shouldNotifyOnFormChanges and didAssociateFormControls to the WKBundlePageFormClient.

* WebProcess/InjectedBundle/API/c/WKBundlePage.h:
Add the new callbacks as part of version 2 of the WKBundlePageFormClient.

* WebProcess/InjectedBundle/InjectedBundlePageFormClient.cpp:
(WebKit::InjectedBundlePageFormClient::didAssociateFormControls):
Pass the message along to the client if the client has a handler.
(WebKit::InjectedBundlePageFormClient::shouldNotifyOnFormChanges):
Ditto.
* WebProcess/InjectedBundle/InjectedBundlePageFormClient.h:

* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::didAssociateFormControls):
Tell the injected bundle form client for the page.
(WebKit::WebChromeClient::shouldNotifyOnFormChanges):
Ditto.
* WebProcess/WebCoreSupport/WebChromeClient.h:

Tools:

Add tests for the new callbacks.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
Add DidAssociateFormControls/_Bundle.cpp and associate-form-controls.html

* TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp: Added.
(TestWebKitAPI::nullJavaScriptCallback):
A "null" callback to handle the fact that WKPageRunJavaScriptInMainFrame cannot handle null
being passed in for the callback.
(TestWebKitAPI::didReceiveMessageFromInjectedBundle):
After receiving the message that didAssociateFormControls callback was invoked from adding
the form in the onload handler, tell the page to add a password field to the form, which
should also invoke didAssociateFormControls callback.
(TestWebKitAPI::setInjectedBundleClient):
Register to receive messages.
(TestWebKitAPI::TEST):
Load associate-form-controls.html and wait until the didAssociateFormControls callback has
been invoked for both adding the form and for adding a password field to the form.

* TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp: Added.
(TestWebKitAPI::shouldNotifyOnFormChanges):
Return true so the didAssociateFormControls callback is invoked.
(TestWebKitAPI::didAssociateFormControls):
Tell the UI process.
(TestWebKitAPI::DidAssociateFormControlsTest::DidAssociateFormControlsTest):
(TestWebKitAPI::DidAssociateFormControlsTest::didCreatePage):
Register for the shouldNotifyOnFormChanges and didAssociateFormControls callbacks.

* TestWebKitAPI/Tests/WebKit2/associate-form-controls.html: Added.
Add a form in response to the onload event. Add a button that will add the password field
for manual testing.

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

Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/InjectedBundle/API/c/WKBundlePage.h
Source/WebKit2/WebProcess/InjectedBundle/InjectedBundlePageFormClient.cpp
Source/WebKit2/WebProcess/InjectedBundle/InjectedBundlePageFormClient.h
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html [new file with mode: 0644]

index 8c82619..68a2f8a 100644 (file)
@@ -1,3 +1,30 @@
+2013-05-21  Jessie Berlin  <jberlin@apple.com>
+
+        Expose a way to know when forms are added to a page or when form controls are added to a form
+        in the injected bundle
+        https://bugs.webkit.org/show_bug.cgi?id=116334
+
+        Reviewed by Alexey Proskuryakov.
+
+        Add shouldNotifyOnFormChanges and didAssociateFormControls to the WKBundlePageFormClient.
+
+        * WebProcess/InjectedBundle/API/c/WKBundlePage.h:
+        Add the new callbacks as part of version 2 of the WKBundlePageFormClient.
+
+        * WebProcess/InjectedBundle/InjectedBundlePageFormClient.cpp:
+        (WebKit::InjectedBundlePageFormClient::didAssociateFormControls):
+        Pass the message along to the client if the client has a handler.
+        (WebKit::InjectedBundlePageFormClient::shouldNotifyOnFormChanges):
+        Ditto.
+        * WebProcess/InjectedBundle/InjectedBundlePageFormClient.h:
+
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::didAssociateFormControls):
+        Tell the injected bundle form client for the page.
+        (WebKit::WebChromeClient::shouldNotifyOnFormChanges):
+        Ditto.
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+
 2013-05-21  Michael BrĂ¼ning  <michael.bruning@digia.com>
 
         [Qt][WK2] Fix Mountain Lion builds after r150277.
index 99550c3..103f478 100644 (file)
@@ -338,6 +338,8 @@ typedef bool (*WKBundlePageShouldPerformActionInTextFieldCallback)(WKBundlePageR
 typedef void (*WKBundlePageWillSubmitFormCallback)(WKBundlePageRef page, WKBundleNodeHandleRef htmlFormElementHandle, WKBundleFrameRef frame, WKBundleFrameRef sourceFrame, WKDictionaryRef values, WKTypeRef* userData, const void* clientInfo);
 typedef void (*WKBundlePageWillSendSubmitEventCallback)(WKBundlePageRef page, WKBundleNodeHandleRef htmlFormElementHandle, WKBundleFrameRef frame, WKBundleFrameRef sourceFrame, WKDictionaryRef values, const void* clientInfo);
 typedef void (*WKBundlePageDidFocusTextFieldCallback)(WKBundlePageRef page, WKBundleNodeHandleRef htmlInputElementHandle, WKBundleFrameRef frame, const void* clientInfo);
+typedef bool (*WKBundlePageShouldNotifyOnFormChangesCallback)(WKBundlePageRef page, const void* clientInfo);
+typedef void (*WKBundlePageDidAssociateFormControlsCallback)(WKBundlePageRef page, WKArrayRef elementHandles, const void* clientInfo);
 
 struct WKBundlePageFormClient {
     int                                                                 version;
@@ -356,6 +358,8 @@ struct WKBundlePageFormClient {
 
     // version 2.
     WKBundlePageDidFocusTextFieldCallback                               didFocusTextField;
+    WKBundlePageShouldNotifyOnFormChangesCallback                       shouldNotifyOnFormChanges;
+    WKBundlePageDidAssociateFormControlsCallback                        didAssociateFormControls;
 };
 typedef struct WKBundlePageFormClient WKBundlePageFormClient;
 
index dea5eab..3af6cf4 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "InjectedBundlePageFormClient.h"
 
+#include "ImmutableArray.h"
 #include "ImmutableDictionary.h"
 #include "InjectedBundleNodeHandle.h"
 #include "WKAPICast.h"
@@ -124,4 +125,28 @@ void InjectedBundlePageFormClient::willSubmitForm(WebPage* page, HTMLFormElement
     userData = adoptRef(toImpl(userDataToPass));
 }
 
+void InjectedBundlePageFormClient::didAssociateFormControls(WebPage* page, const Vector<RefPtr<WebCore::Element>>& elements)
+{
+    if (!m_client.didAssociateFormControls)
+        return;
+
+    size_t size = elements.size();
+
+    Vector<RefPtr<APIObject>> elementHandles;
+    elementHandles.reserveCapacity(size);
+
+    for (size_t i = 0; i < size; ++i)
+        elementHandles.uncheckedAppend(InjectedBundleNodeHandle::getOrCreate(elements[i].get()).get());
+
+    m_client.didAssociateFormControls(toAPI(page), toAPI(ImmutableArray::adopt(elementHandles).get()), m_client.clientInfo);
+}
+
+bool InjectedBundlePageFormClient::shouldNotifyOnFormChanges(WebPage* page)
+{
+    if (!m_client.shouldNotifyOnFormChanges)
+        return false;
+
+    return m_client.shouldNotifyOnFormChanges(toAPI(page), m_client.clientInfo);
+}
+
 } // namespace WebKit
index 9605acb..47bbc72 100644 (file)
 #include <wtf/Vector.h>
 
 namespace WebCore {
-    class HTMLFormElement;
-    class HTMLInputElement;
-    class HTMLTextAreaElement;
+class Element;
+class HTMLFormElement;
+class HTMLInputElement;
+class HTMLTextAreaElement;
 }
 
 namespace WebKit {
@@ -55,6 +56,8 @@ public:
     bool shouldPerformActionInTextField(WebPage*, WebCore::HTMLInputElement*, WKInputFieldActionType, WebFrame*);    
     void willSubmitForm(WebPage*, WebCore::HTMLFormElement*, WebFrame*, WebFrame* sourceFrame, const Vector<std::pair<String, String>>&, RefPtr<APIObject>& userData);
     void willSendSubmitEvent(WebPage*, WebCore::HTMLFormElement*, WebFrame*, WebFrame* sourceFrame, const Vector<std::pair<String, String>>&);
+    void didAssociateFormControls(WebPage*, const Vector<RefPtr<WebCore::Element>>&);
+    bool shouldNotifyOnFormChanges(WebPage*);
 };
 
 } // namespace WebKit
index 2e2b57a..e8a9a28 100644 (file)
@@ -716,6 +716,16 @@ void WebChromeClient::formStateDidChange(const Node*)
     notImplemented();
 }
 
+void WebChromeClient::didAssociateFormControls(const Vector<RefPtr<WebCore::Element>>& elements)
+{
+    return m_page->injectedBundleFormClient().didAssociateFormControls(m_page, elements);
+}
+
+bool WebChromeClient::shouldNotifyOnFormChanges()
+{
+    return m_page->injectedBundleFormClient().shouldNotifyOnFormChanges(m_page);
+}
+
 bool WebChromeClient::selectItemWritingDirectionIsNatural()
 {
 #if PLATFORM(EFL)
index db704bd..7044b54 100644 (file)
@@ -170,6 +170,9 @@ private:
     // will be called frequently, so handling should be very fast.
     virtual void formStateDidChange(const WebCore::Node*) OVERRIDE;
 
+    virtual void didAssociateFormControls(const Vector<RefPtr<WebCore::Element>>&) OVERRIDE;
+    virtual bool shouldNotifyOnFormChanges() OVERRIDE;
+
     virtual bool selectItemWritingDirectionIsNatural() OVERRIDE;
     virtual bool selectItemAlignmentFollowsMenuWritingDirection() OVERRIDE;
     virtual bool hasOpenedPopup() const OVERRIDE;
index dc692cb..5cb209d 100644 (file)
@@ -1,3 +1,43 @@
+2013-05-21  Jessie Berlin  <jberlin@apple.com>
+
+        Expose a way to know when forms are added to a page or when form controls are added to a form
+        in the injected bundle
+        https://bugs.webkit.org/show_bug.cgi?id=116334
+
+        Reviewed by Alexey Proskuryakov.
+
+        Add tests for the new callbacks.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        Add DidAssociateFormControls/_Bundle.cpp and associate-form-controls.html
+
+        * TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp: Added.
+        (TestWebKitAPI::nullJavaScriptCallback):
+        A "null" callback to handle the fact that WKPageRunJavaScriptInMainFrame cannot handle null
+        being passed in for the callback.
+        (TestWebKitAPI::didReceiveMessageFromInjectedBundle):
+        After receiving the message that didAssociateFormControls callback was invoked from adding
+        the form in the onload handler, tell the page to add a password field to the form, which
+        should also invoke didAssociateFormControls callback.
+        (TestWebKitAPI::setInjectedBundleClient):
+        Register to receive messages.
+        (TestWebKitAPI::TEST):
+        Load associate-form-controls.html and wait until the didAssociateFormControls callback has
+        been invoked for both adding the form and for adding a password field to the form.
+
+        * TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp: Added.
+        (TestWebKitAPI::shouldNotifyOnFormChanges):
+        Return true so the didAssociateFormControls callback is invoked.
+        (TestWebKitAPI::didAssociateFormControls):
+        Tell the UI process.
+        (TestWebKitAPI::DidAssociateFormControlsTest::DidAssociateFormControlsTest):
+        (TestWebKitAPI::DidAssociateFormControlsTest::didCreatePage):
+        Register for the shouldNotifyOnFormChanges and didAssociateFormControls callbacks.
+
+        * TestWebKitAPI/Tests/WebKit2/associate-form-controls.html: Added.
+        Add a form in response to the onload event. Add a button that will add the password field
+        for manual testing.
+
 2013-05-21  Krzysztof Czech  <k.czech@samsung.com>
 
         [GTK][WK2] accessibility/label-for-control-hittest.html is failing
index 56d88d1..8e652a9 100644 (file)
                F660AA1115A5F631003A1243 /* GetInjectedBundleInitializationUserDataCallback_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660AA0F15A5F624003A1243 /* GetInjectedBundleInitializationUserDataCallback_Bundle.cpp */; };
                F660AA1315A619C9003A1243 /* InjectedBundleInitializationUserDataCallbackWins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660AA1215A619C8003A1243 /* InjectedBundleInitializationUserDataCallbackWins.cpp */; };
                F660AA1515A61ABF003A1243 /* InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660AA1415A61ABF003A1243 /* InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp */; };
+               F6B7BE9417469209008A3445 /* DidAssociateFormControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6B7BE93174691EF008A3445 /* DidAssociateFormControls.cpp */; };
+               F6B7BE9517469212008A3445 /* DidAssociateFormControls_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6B7BE92174691EF008A3445 /* DidAssociateFormControls_Bundle.cpp */; };
+               F6B7BE9717469B96008A3445 /* associate-form-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F6B7BE9617469B7E008A3445 /* associate-form-controls.html */; };
                F6F3F29113342FEB00A6BF19 /* CookieManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F3F29013342FEB00A6BF19 /* CookieManager.cpp */; };
                F6F49C6915545C8E0007F39D /* DOMWindowExtensionNoCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F49C6715545C8D0007F39D /* DOMWindowExtensionNoCache.cpp */; };
                F6F49C6B15545CA70007F39D /* DOMWindowExtensionNoCache_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F49C6615545C8D0007F39D /* DOMWindowExtensionNoCache_Bundle.cpp */; };
                                C2CF975B16CEC71B0054E99D /* JSContextBackForwardCache1.html in Copy Resources */,
                                C2CF975A16CEC7140054E99D /* JSContextBackForwardCache2.html in Copy Resources */,
                                1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
+                               F6B7BE9717469B96008A3445 /* associate-form-controls.html in Copy Resources */,
                                379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
                                B55F11BE15191A0600915916 /* Ahem.ttf in Copy Resources */,
                                B55F11B71517D03300915916 /* attributedStringCustomFont.html in Copy Resources */,
                F660AA0F15A5F624003A1243 /* GetInjectedBundleInitializationUserDataCallback_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetInjectedBundleInitializationUserDataCallback_Bundle.cpp; sourceTree = "<group>"; };
                F660AA1215A619C8003A1243 /* InjectedBundleInitializationUserDataCallbackWins.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleInitializationUserDataCallbackWins.cpp; sourceTree = "<group>"; };
                F660AA1415A61ABF003A1243 /* InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp; sourceTree = "<group>"; };
+               F6B7BE92174691EF008A3445 /* DidAssociateFormControls_Bundle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DidAssociateFormControls_Bundle.cpp; sourceTree = "<group>"; };
+               F6B7BE93174691EF008A3445 /* DidAssociateFormControls.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DidAssociateFormControls.cpp; sourceTree = "<group>"; };
+               F6B7BE9617469B7E008A3445 /* associate-form-controls.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "associate-form-controls.html"; sourceTree = "<group>"; };
                F6F3F29013342FEB00A6BF19 /* CookieManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CookieManager.cpp; sourceTree = "<group>"; };
                F6F49C6615545C8D0007F39D /* DOMWindowExtensionNoCache_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtensionNoCache_Bundle.cpp; sourceTree = "<group>"; };
                F6F49C6715545C8D0007F39D /* DOMWindowExtensionNoCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtensionNoCache.cpp; sourceTree = "<group>"; };
                                BC246D98132F1FE100B56D7C /* CanHandleRequest.cpp */,
                                BC246D97132F1FE100B56D7C /* CanHandleRequest_Bundle.cpp */,
                                F6F3F29013342FEB00A6BF19 /* CookieManager.cpp */,
+                               F6B7BE93174691EF008A3445 /* DidAssociateFormControls.cpp */,
+                               F6B7BE92174691EF008A3445 /* DidAssociateFormControls_Bundle.cpp */,
                                BCB6803F126FBFE100642A61 /* DocumentStartUserScriptAlertCrash.cpp */,
                                BCB68041126FBFF100642A61 /* DocumentStartUserScriptAlertCrash_Bundle.cpp */,
                                51393E1E1523944A005F39C5 /* DOMWindowExtensionBasic.cpp */,
                        isa = PBXGroup;
                        children = (
                                C045F9461385C2F800C0F3CD /* 18-characters.html */,
+                               F6B7BE9617469B7E008A3445 /* associate-form-controls.html */,
                                76E182DE15475A8300F1FADD /* auto-submitting-form.html */,
                                290F4274172A1FDE00939FF0 /* custom-protocol-sync-xhr.html */,
                                C5E1AFFD16B22179006CC1F2 /* execCopy.html */,
                                37E38C34169B7D010084C28C /* WebViewDidRemoveFrameFromHierarchy.mm in Sources */,
                                76E182DA1547550100F1FADD /* WillSendSubmitEvent.cpp in Sources */,
                                A5E2027315B2181900C13E14 /* WindowlessWebViewWithMedia.mm in Sources */,
+                               F6B7BE9417469209008A3445 /* DidAssociateFormControls.cpp in Sources */,
                                BC3C4C7F14587AA60025FB62 /* WKBrowsingContextGroupTest.mm in Sources */,
                                BC3C4C7214575B6A0025FB62 /* WKBrowsingContextLoadDelegateTest.mm in Sources */,
                                BC901E241492ADCE0074A667 /* WKConnection.cpp in Sources */,
                                7CFBCAE51743238F00B2BFCF /* WillLoad_Bundle.cpp in Sources */,
                                BC575BD9126F58E2006F0F12 /* PlatformUtilities.cpp in Sources */,
                                BC575BE0126F590D006F0F12 /* PlatformUtilitiesMac.mm in Sources */,
+                               F6B7BE9517469212008A3445 /* DidAssociateFormControls_Bundle.cpp in Sources */,
                                C0BD669F131D3CFF00E18F2A /* ResponsivenessTimerDoesntFireEarly_Bundle.cpp in Sources */,
                                51FCF7A11534B2A000104491 /* ShouldGoToBackForwardListItem_Bundle.cpp in Sources */,
                                BC22D31914DC68B900FFB1DD /* UserMessage_Bundle.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp
new file mode 100644 (file)
index 0000000..4e6b4fe
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+
+namespace TestWebKitAPI {
+
+static bool didReceiveAllMessages = false;
+static bool receivedMessageForAddingForm = false;
+static const uint64_t expectedNumberOfElements = 1;
+
+static void nullJavaScriptCallback(WKSerializedScriptValueRef, WKErrorRef, void*)
+{
+}
+
+static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*)
+{
+    EXPECT_WK_STREQ("DidReceiveDidAssociateFormControls", messageName);
+    ASSERT_NOT_NULL(messageBody);
+    EXPECT_EQ(WKDictionaryGetTypeID(), WKGetTypeID(messageBody));
+
+    WKDictionaryRef dictionary = static_cast<WKDictionaryRef>(messageBody);
+    uint64_t numberOfElements = WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(dictionary, Util::toWK("NumberOfControls").get())));
+
+    EXPECT_EQ(expectedNumberOfElements, numberOfElements);
+
+    if (!receivedMessageForAddingForm) {
+        receivedMessageForAddingForm = true;
+
+        WKPageRef page = static_cast<WKPageRef>(WKDictionaryGetItemForKey(dictionary, Util::toWK("Page").get()));
+        WKPageRunJavaScriptInMainFrame(page, Util::toWK("addPasswordFieldToForm()").get(), 0, nullJavaScriptCallback);
+
+        return;
+    }
+
+    didReceiveAllMessages = true;
+}
+
+static void setInjectedBundleClient(WKContextRef context)
+{
+    WKContextInjectedBundleClient injectedBundleClient;
+    memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+    injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle;
+
+    WKContextSetInjectedBundleClient(context, &injectedBundleClient);
+}
+
+TEST(WebKit2, DidAssociateFormControls)
+{
+    WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("DidAssociateFormControlsTest"));
+    setInjectedBundleClient(context.get());
+
+    PlatformWebView webView(context.get());
+    WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("associate-form-controls", "html")).get());
+    Util::run(&didReceiveAllMessages);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp
new file mode 100644 (file)
index 0000000..b742650
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InjectedBundleTest.h"
+
+#include "PlatformUtilities.h"
+#include <WebKit2/WKBundle.h>
+#include <WebKit2/WKBundlePage.h>
+
+namespace TestWebKitAPI {
+
+class DidAssociateFormControlsTest : public InjectedBundleTest {
+public:
+    DidAssociateFormControlsTest(const std::string& identifier);
+
+    virtual void didCreatePage(WKBundleRef, WKBundlePageRef) OVERRIDE;
+};
+
+static InjectedBundleTest::Register<DidAssociateFormControlsTest> registrar("DidAssociateFormControlsTest");
+
+static bool shouldNotifyOnFormChanges(WKBundlePageRef, const void*)
+{
+    return true;
+}
+
+static void didAssociateFormControls(WKBundlePageRef page, WKArrayRef elementHandles, const void*)
+{
+    WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate());
+
+    WKDictionaryAddItem(messageBody.get(), Util::toWK("Page").get(), page);
+    WKRetainPtr<WKUInt64Ref> numberOfElements = adoptWK(WKUInt64Create(WKArrayGetSize(elementHandles)));
+    WKDictionaryAddItem(messageBody.get(), Util::toWK("NumberOfControls").get(), numberOfElements.get());
+
+    WKBundlePostMessage(InjectedBundleController::shared().bundle(), Util::toWK("DidReceiveDidAssociateFormControls").get(), messageBody.get());
+}
+
+DidAssociateFormControlsTest::DidAssociateFormControlsTest(const std::string& identifier)
+    : InjectedBundleTest(identifier)
+{
+}
+
+void DidAssociateFormControlsTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+{
+    WKBundlePageFormClient formClient;
+    memset(&formClient, 0, sizeof(formClient));
+
+    formClient.version = 2;
+    formClient.clientInfo = this;
+    formClient.shouldNotifyOnFormChanges = shouldNotifyOnFormChanges;
+    formClient.didAssociateFormControls = didAssociateFormControls;
+
+    WKBundlePageSetFormClient(page, &formClient);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html
new file mode 100644 (file)
index 0000000..906246a
--- /dev/null
@@ -0,0 +1,31 @@
+<html>
+<head>
+  <script>
+    function addForm()
+    {
+        var form = document.createElement("form");
+        form.id = "login_form";
+
+        var usernameField = document.createElement("input");
+        usernameField.id = "username";
+        usernameField.type = "text";
+        form.appendChild(usernameField);
+
+        document.body.appendChild(form);
+    }
+
+    function addPasswordFieldToForm()
+    {
+        var passwordField = document.createElement("input");
+        passwordField.id = "password";
+        passwordField.type = "password";
+
+        var form = document.getElementById("login_form");
+        form.appendChild(passwordField);
+    }
+  </script>
+</head>
+<body onload="addForm()">
+<button onclick="addPasswordFieldToForm()">Manual Testing: Add the password field</button>
+</body>
+</html>