<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[208532] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/208532">208532</a></dd>
<dt>Author</dt> <dd>svillar@igalia.com</dd>
<dt>Date</dt> <dd>2016-11-10 02:15:30 -0800 (Thu, 10 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[GTK] New API to notify about dynamically added forms
https://bugs.webkit.org/show_bug.cgi?id=164050

Reviewed by Carlos Garcia Campos.

Source/WebKit2:

This new API exports the WebCore event didAssociateFormControls through the web extension
mechanism. This will help clients (mainly web browsers) to implement robust auto filling
mechanisms. It deals nicely with dynamically created forms (and form controls) as many JS
frameworks do nowadays.

* WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp: Added a FormClient implementation of
API::InjectedBundle::FormClient.
(webkitWebPageFormControlsAssociated): Emit the new signal.
(webkit_web_page_class_init): Added the new signal &quot;forms-controls-associated&quot;.
(webkitWebPageCreate): Set the WebPage as a FormClient.

Tools:

Added a new test case to verify that dinamically added forms correctly trigger the
&quot;form-controls-associated&quot; signal from WebPage.

* TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp:
(didAssociateFormControlsCallback):
(testWebExtensionFormControlsAssociated):
(beforeAll):
* TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp:
(DelayedSignal::DelayedSignal):
(emitFormControlsAssociated):
(formControlsAssociatedCallback):
(pageCreatedCallback):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2WebProcessInjectedBundleAPIgtkWebKitWebPagecpp">trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2GtkTestWebExtensionscpp">trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2GtkWebExtensionTestcpp">trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (208531 => 208532)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-11-10 10:08:19 UTC (rev 208531)
+++ trunk/Source/WebKit2/ChangeLog        2016-11-10 10:15:30 UTC (rev 208532)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2016-10-27  Sergio Villar Senin  &lt;svillar@igalia.com&gt;
+
+        [GTK] New API to notify about dynamically added forms
+        https://bugs.webkit.org/show_bug.cgi?id=164050
+
+        Reviewed by Carlos Garcia Campos.
+
+        This new API exports the WebCore event didAssociateFormControls through the web extension
+        mechanism. This will help clients (mainly web browsers) to implement robust auto filling
+        mechanisms. It deals nicely with dynamically created forms (and form controls) as many JS
+        frameworks do nowadays.
+
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp: Added a FormClient implementation of
+        API::InjectedBundle::FormClient.
+        (webkitWebPageFormControlsAssociated): Emit the new signal.
+        (webkit_web_page_class_init): Added the new signal &quot;forms-controls-associated&quot;.
+        (webkitWebPageCreate): Set the WebPage as a FormClient.
+
</ins><span class="cx"> 2016-11-10  Carlos Alberto Lopez Perez  &lt;clopez@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Allow to use WebMemorySampler feature.
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessInjectedBundleAPIgtkWebKitWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp (208531 => 208532)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp        2016-11-10 10:08:19 UTC (rev 208531)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp        2016-11-10 10:15:30 UTC (rev 208532)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;WebKitConsoleMessagePrivate.h&quot;
</span><span class="cx"> #include &quot;WebKitContextMenuPrivate.h&quot;
</span><span class="cx"> #include &quot;WebKitDOMDocumentPrivate.h&quot;
</span><ins>+#include &quot;WebKitDOMElementPrivate.h&quot;
</ins><span class="cx"> #include &quot;WebKitFramePrivate.h&quot;
</span><span class="cx"> #include &quot;WebKitMarshal.h&quot;
</span><span class="cx"> #include &quot;WebKitPrivate.h&quot;
</span><span class="lines">@@ -60,6 +61,7 @@
</span><span class="cx">     SEND_REQUEST,
</span><span class="cx">     CONTEXT_MENU,
</span><span class="cx">     CONSOLE_MESSAGE_SENT,
</span><ins>+    FORM_CONTROLS_ASSOCIATED,
</ins><span class="cx"> 
</span><span class="cx">     LAST_SIGNAL
</span><span class="cx"> };
</span><span class="lines">@@ -340,6 +342,28 @@
</span><span class="cx">     WebKitWebPage* m_webPage;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class FormClient final : public API::InjectedBundle::FormClient {
+public:
+    explicit FormClient(WebKitWebPage* webPage)
+        : m_webPage(webPage)
+    {
+    }
+
+    void didAssociateFormControls(WebPage*, const Vector&lt;RefPtr&lt;Element&gt;&gt;&amp; elements) override
+    {
+        GRefPtr&lt;GPtrArray&gt; formElements = adoptGRef(g_ptr_array_sized_new(elements.size()));
+        for (size_t i = 0; i &lt; elements.size(); ++i)
+            g_ptr_array_add(formElements.get(), WebKit::kit(elements[i].get()));
+
+        g_signal_emit(m_webPage, signals[FORM_CONTROLS_ASSOCIATED], 0, formElements.get());
+    }
+
+    bool shouldNotifyOnFormChanges(WebPage*) override { return true; }
+
+private:
+    WebKitWebPage* m_webPage;
+};
+
</ins><span class="cx"> static void webkitWebPageGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
</span><span class="cx"> {
</span><span class="cx">     WebKitWebPage* webPage = WEBKIT_WEB_PAGE(object);
</span><span class="lines">@@ -473,6 +497,33 @@
</span><span class="cx">         g_cclosure_marshal_VOID__BOXED,
</span><span class="cx">         G_TYPE_NONE, 1,
</span><span class="cx">         WEBKIT_TYPE_CONSOLE_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE);
</span><ins>+
+    /**
+     * WebKitWebPage::form-controls-associated:
+     * @web_page: the #WebKitWebPage on which the signal is emitted
+     * @elements: (element-type WebKit.DOMElement) (transfer none): a #GPtrArray of
+     *     #WebKitDOMElement with the list of forms in the page
+     *
+     * Emitted after form elements (or form associated elements) are associated to a particular web
+     * page. Useful to implement form autofilling with web pages where form fields are dynamically
+     * added (as many JS frameworks do). This might be emitted multiple times for the same web page.
+     *
+     * Note that this signal could be also emitted when form controls are moved between forms. In
+     * those cases the @elements array carries the list of those elements which have moved.
+     *
+     * In any case the members of the @elements array will be alive during signal emission so
+     * clients should take a reference to keep them alive.
+     *
+     * Since: 2.16
+     */
+    signals[FORM_CONTROLS_ASSOCIATED] = g_signal_new(
+        &quot;form-controls-associated&quot;,
+        G_TYPE_FROM_CLASS(klass),
+        G_SIGNAL_RUN_LAST,
+        0, 0, nullptr,
+        g_cclosure_marshal_VOID__BOXED,
+        G_TYPE_NONE, 1,
+        G_TYPE_PTR_ARRAY);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> WebPage* webkitWebPageGetPage(WebKitWebPage *webPage)
</span><span class="lines">@@ -545,6 +596,7 @@
</span><span class="cx"> 
</span><span class="cx">     webPage-&gt;setInjectedBundleContextMenuClient(std::make_unique&lt;PageContextMenuClient&gt;(page));
</span><span class="cx">     webPage-&gt;setInjectedBundleUIClient(std::make_unique&lt;PageUIClient&gt;(page));
</span><ins>+    webPage-&gt;setInjectedBundleFormClient(std::make_unique&lt;FormClient&gt;(page));
</ins><span class="cx"> 
</span><span class="cx">     return page;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (208531 => 208532)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-11-10 10:08:19 UTC (rev 208531)
+++ trunk/Tools/ChangeLog        2016-11-10 10:15:30 UTC (rev 208532)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2016-10-27  Sergio Villar Senin  &lt;svillar@igalia.com&gt;
+
+        [GTK] New API to notify about dynamically added forms
+        https://bugs.webkit.org/show_bug.cgi?id=164050
+
+        Reviewed by Carlos Garcia Campos.
+
+        Added a new test case to verify that dinamically added forms correctly trigger the
+        &quot;form-controls-associated&quot; signal from WebPage.
+
+        * TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp:
+        (didAssociateFormControlsCallback):
+        (testWebExtensionFormControlsAssociated):
+        (beforeAll):
+        * TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp:
+        (DelayedSignal::DelayedSignal):
+        (emitFormControlsAssociated):
+        (formControlsAssociatedCallback):
+        (pageCreatedCallback):
+
</ins><span class="cx"> 2016-11-09  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         WebHTMLView's _attributeStringFromDOMRange should use HTMLConverter instead of NSAttributedString's _initWithDOMRange
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2GtkTestWebExtensionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp (208531 => 208532)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp        2016-11-10 10:08:19 UTC (rev 208531)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp        2016-11-10 10:15:30 UTC (rev 208532)
</span><span class="lines">@@ -27,6 +27,10 @@
</span><span class="cx"> static WebKitTestBus* bus;
</span><span class="cx"> static GUniquePtr&lt;char&gt; scriptDialogResult;
</span><span class="cx"> 
</span><ins>+#define INPUT_ID &quot;input-id&quot;
+#define FORM_ID &quot;form-id&quot;
+#define FORM2_ID &quot;form2-id&quot;
+
</ins><span class="cx"> static void testWebExtensionGetTitle(WebViewTest* test, gconstpointer)
</span><span class="cx"> {
</span><span class="cx">     test-&gt;loadHtml(&quot;&lt;html&gt;&lt;head&gt;&lt;title&gt;WebKitGTK+ Web Extensions Test&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;&quot;, 0);
</span><span class="lines">@@ -212,6 +216,65 @@
</span><span class="cx">     g_signal_handler_disconnect(test-&gt;m_webView, permissionRequestSignalID);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void didAssociateFormControlsCallback(GDBusConnection*, const char*, const char*, const char*, const char*, GVariant* result, WebViewTest* test)
+{
+    const char* formIds;
+    g_variant_get(result, &quot;(&amp;s)&quot;, &amp;formIds);
+    g_assert(!g_strcmp0(formIds, FORM_ID FORM2_ID) || !g_strcmp0(formIds, INPUT_ID));
+
+    test-&gt;quitMainLoop();
+}
+
+static void testWebExtensionFormControlsAssociated(WebViewTest* test, gconstpointer)
+{
+    GUniquePtr&lt;char&gt; extensionBusName(g_strdup_printf(&quot;org.webkit.gtk.WebExtensionTest%u&quot;, Test::s_webExtensionID));
+    GRefPtr&lt;GDBusProxy&gt; proxy = adoptGRef(bus-&gt;createProxy(extensionBusName.get(),
+        &quot;/org/webkit/gtk/WebExtensionTest&quot;, &quot;org.webkit.gtk.WebExtensionTest&quot;, test-&gt;m_mainLoop));
+    GDBusConnection* connection = g_dbus_proxy_get_connection(proxy.get());
+    guint id = g_dbus_connection_signal_subscribe(connection,
+        nullptr,
+        &quot;org.webkit.gtk.WebExtensionTest&quot;,
+        &quot;FormControlsAssociated&quot;,
+        &quot;/org/webkit/gtk/WebExtensionTest&quot;,
+        nullptr,
+        G_DBUS_SIGNAL_FLAGS_NONE,
+        reinterpret_cast&lt;GDBusSignalCallback&gt;(didAssociateFormControlsCallback),
+        test,
+        nullptr);
+    g_assert(id);
+
+    test-&gt;loadHtml(&quot;&lt;!DOCTYPE html&gt;&lt;head&gt;&lt;title&gt;WebKitGTK+ Web Extensions Test&lt;/title&gt;&lt;/head&gt;&lt;div id=\&quot;placeholder\&quot;/&gt;&quot;, 0);
+    test-&gt;waitUntilLoadFinished();
+
+    static const char* addFormScript =
+        &quot;var input = document.createElement(\&quot;input\&quot;);&quot;
+        &quot;input.id = \&quot;&quot; INPUT_ID &quot;\&quot;;&quot;
+        &quot;input.type = \&quot;password\&quot;;&quot;
+        &quot;var form = document.createElement(\&quot;form\&quot;);&quot;
+        &quot;form.id = \&quot;&quot; FORM_ID &quot;\&quot;;&quot;
+        &quot;form.appendChild(input);&quot;
+        &quot;var form2 = document.createElement(\&quot;form\&quot;);&quot;
+        &quot;form2.id = \&quot;&quot; FORM2_ID &quot;\&quot;;&quot;
+        &quot;var placeholder = document.getElementById(\&quot;placeholder\&quot;);&quot;
+        &quot;placeholder.appendChild(form);&quot;
+        &quot;placeholder.appendChild(form2);&quot;;
+
+    webkit_web_view_run_javascript(test-&gt;m_webView, addFormScript, nullptr, nullptr, nullptr);
+    g_main_loop_run(test-&gt;m_mainLoop);
+
+    static const char* moveFormElementScript =
+        &quot;var form = document.getElementById(\&quot;&quot; FORM_ID &quot;\&quot;);&quot;
+        &quot;var form2 = document.getElementById(\&quot;&quot; FORM2_ID &quot;\&quot;);&quot;
+        &quot;var input = document.getElementById(\&quot;&quot; INPUT_ID &quot;\&quot;);&quot;
+        &quot;form.removeChild(input);&quot;
+        &quot;form2.appendChild(input);&quot;;
+
+    webkit_web_view_run_javascript(test-&gt;m_webView, moveFormElementScript, nullptr, nullptr, nullptr);
+    g_main_loop_run(test-&gt;m_mainLoop);
+
+    g_dbus_connection_signal_unsubscribe(connection, id);
+}
+
</ins><span class="cx"> void beforeAll()
</span><span class="cx"> {
</span><span class="cx">     bus = new WebKitTestBus();
</span><span class="lines">@@ -224,6 +287,7 @@
</span><span class="cx">     WebViewTest::add(&quot;WebKitWebExtension&quot;, &quot;window-object-cleared&quot;, testWebExtensionWindowObjectCleared);
</span><span class="cx">     WebViewTest::add(&quot;WebKitWebExtension&quot;, &quot;isolated-world&quot;, testWebExtensionIsolatedWorld);
</span><span class="cx">     WebViewTest::add(&quot;WebKitWebView&quot;, &quot;install-missing-plugins-permission-request&quot;, testInstallMissingPluginsPermissionRequest);
</span><ins>+    WebViewTest::add(&quot;WebKitWebExtension&quot;, &quot;form-controls-associated-signal&quot;, testWebExtensionFormControlsAssociated);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void afterAll()
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2GtkWebExtensionTestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp (208531 => 208532)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp        2016-11-10 10:08:19 UTC (rev 208531)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp        2016-11-10 10:15:30 UTC (rev 208532)
</span><span class="lines">@@ -51,6 +51,9 @@
</span><span class="cx">     &quot;  &lt;method name='RemoveAVPluginsFromGSTRegistry'&gt;&quot;
</span><span class="cx">     &quot;  &lt;/method&gt;&quot;
</span><span class="cx">     &quot;  &lt;signal name='DocumentLoaded'/&gt;&quot;
</span><ins>+    &quot;  &lt;signal name='FormControlsAssociated'&gt;&quot;
+    &quot;   &lt;arg type='s' name='formIds' direction='out'/&gt;&quot;
+    &quot;  &lt;/signal&gt;&quot;
</ins><span class="cx">     &quot;  &lt;signal name='URIChanged'&gt;&quot;
</span><span class="cx">     &quot;   &lt;arg type='s' name='uri' direction='out'/&gt;&quot;
</span><span class="cx">     &quot;  &lt;/signal&gt;&quot;
</span><span class="lines">@@ -61,6 +64,7 @@
</span><span class="cx"> typedef enum {
</span><span class="cx">     DocumentLoadedSignal,
</span><span class="cx">     URIChangedSignal,
</span><ins>+    FormControlsAssociatedSignal,
</ins><span class="cx"> } DelayedSignalType;
</span><span class="cx"> 
</span><span class="cx"> struct DelayedSignal {
</span><span class="lines">@@ -69,14 +73,14 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    DelayedSignal(DelayedSignalType type, const char* uri)
</del><ins>+    DelayedSignal(DelayedSignalType type, const char* str)
</ins><span class="cx">         : type(type)
</span><del>-        , uri(uri)
</del><ins>+        , str(str)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     DelayedSignalType type;
</span><del>-    CString uri;
</del><ins>+    CString str;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> Deque&lt;DelayedSignal&gt; delayedSignalsQueue;
</span><span class="lines">@@ -238,6 +242,36 @@
</span><span class="cx">     webkit_dom_dom_window_webkit_message_handlers_post_message(window.get(), &quot;console&quot;, messageString.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+static void emitFormControlsAssociated(GDBusConnection* connection, const char* formIds)
+{
+    bool ok = g_dbus_connection_emit_signal(
+        connection,
+        nullptr,
+        &quot;/org/webkit/gtk/WebExtensionTest&quot;,
+        &quot;org.webkit.gtk.WebExtensionTest&quot;,
+        &quot;FormControlsAssociated&quot;,
+        g_variant_new(&quot;(s)&quot;, formIds),
+        nullptr);
+    g_assert(ok);
+}
+
+static void formControlsAssociatedCallback(WebKitWebPage* webPage, GPtrArray* formElements, WebKitWebExtension* extension)
+{
+    GString* formIdsBuilder = g_string_new(nullptr);
+    for (int i = 0; i &lt; formElements-&gt;len; ++i) {
+        g_assert(WEBKIT_DOM_IS_ELEMENT(g_ptr_array_index(formElements, i)));
+        auto domElement = WEBKIT_DOM_ELEMENT(g_ptr_array_index(formElements, i));
+        g_string_append(formIdsBuilder, webkit_dom_element_get_id(domElement));
+    }
+    GUniquePtr&lt;char&gt; formIds(g_string_free(formIdsBuilder, FALSE));
+    gpointer data = g_object_get_data(G_OBJECT(extension), &quot;dbus-connection&quot;);
+    if (data)
+        emitFormControlsAssociated(G_DBUS_CONNECTION(data), formIds.get());
+    else
+        delayedSignalsQueue.append(DelayedSignal(FormControlsAssociatedSignal, formIds.get()));
+}
+
</ins><span class="cx"> static void pageCreatedCallback(WebKitWebExtension* extension, WebKitWebPage* webPage, gpointer)
</span><span class="cx"> {
</span><span class="cx">     g_signal_connect(webPage, &quot;document-loaded&quot;, G_CALLBACK(documentLoadedCallback), extension);
</span><span class="lines">@@ -245,6 +279,7 @@
</span><span class="cx">     g_signal_connect(webPage, &quot;send-request&quot;, G_CALLBACK(sendRequestCallback), nullptr);
</span><span class="cx">     g_signal_connect(webPage, &quot;context-menu&quot;, G_CALLBACK(contextMenuCallback), nullptr);
</span><span class="cx">     g_signal_connect(webPage, &quot;console-message-sent&quot;, G_CALLBACK(consoleMessageSentCallback), nullptr);
</span><ins>+    g_signal_connect(webPage, &quot;form-controls-associated&quot;, G_CALLBACK(formControlsAssociatedCallback), extension);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static JSValueRef echoCallback(JSContextRef jsContext, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef*)
</span><span class="lines">@@ -361,8 +396,11 @@
</span><span class="cx">             emitDocumentLoaded(connection);
</span><span class="cx">             break;
</span><span class="cx">         case URIChangedSignal:
</span><del>-            emitURIChanged(connection, delayedSignal.uri.data());
</del><ins>+            emitURIChanged(connection, delayedSignal.str.data());
</ins><span class="cx">             break;
</span><ins>+        case FormControlsAssociatedSignal:
+            emitFormControlsAssociated(connection, delayedSignal.str.data());
+            break;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>