[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

loislo at chromium.org loislo at chromium.org
Wed Dec 22 11:38:28 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 6a07f07ffe5acc63ca14e52486c2bd1162f8bea6
Author: loislo at chromium.org <loislo at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Aug 2 12:55:56 2010 +0000

    ndrey Kosyakov  <caseq at chromium.org>
    
            Reviewed by Pavel Feldman.
    
            Web Inspector: adding experimental support for WebInspector extensions API.
            https://bugs.webkit.org/show_bug.cgi?id=40425
    
            Tests: inspector/extensions-api.html
                   inspector/extensions.html
    
            * WebCore.gypi:
            * WebCore.vcproj/WebCore.vcproj:
            * inspector/InspectorController.cpp:
            (WebCore::InspectorController::inspectedWindowScriptObjectCleared):
            (WebCore::InspectorController::didCommitLoad):
            * inspector/InspectorFrontendHost.cpp:
            (WebCore::InspectorFrontendHost::setExtensionAPI):
            * inspector/InspectorFrontendHost.h:
            * inspector/InspectorFrontendHost.idl:
            * inspector/front-end/ElementsPanel.js:
            (WebInspector.ElementsPanel.this.treeOutline.focusedNodeChanged):
            (WebInspector.ElementsPanel):
            * inspector/front-end/ExtensionAPI.js: Added. An API implementation that gets injected into the extension context.
            (injectedExtensionAPI):
            (injectedExtensionAPI.EventSinkImpl.prototype.addListener):
            (injectedExtensionAPI.EventSinkImpl.prototype.removeListener):
            (injectedExtensionAPI.EventSinkImpl.prototype._fire):
            (injectedExtensionAPI.EventSink):
            (injectedExtensionAPI.InspectorExtensionAPI):
            (injectedExtensionAPI.InspectorExtensionAPI.prototype.log):
            (injectedExtensionAPI.Resources.prototype.getAll):
            (injectedExtensionAPI.Resources.prototype.get return):
            (injectedExtensionAPI.Resources.prototype):
            (injectedExtensionAPI.Panels):
            (injectedExtensionAPI.Panels.prototype.create.callbackWrapper):
            (injectedExtensionAPI.Panels.prototype.create):
            (injectedExtensionAPI.PanelImpl):
            (injectedExtensionAPI.PanelImpl.prototype.createSidebarPane.callbackWrapper):
            (injectedExtensionAPI.PanelImpl.prototype.createSidebarPane):
            (injectedExtensionAPI.ExtensionPanel):
            (injectedExtensionAPI.ExtensionSidebarPaneImpl):
            (injectedExtensionAPI.ExtensionSidebarPaneImpl.prototype.setHeight):
            (injectedExtensionAPI.ExtensionSidebarPaneImpl.prototype.setExpanded):
            (injectedExtensionAPI.InspectedWindow):
            (injectedExtensionAPI.InspectedWindow.prototype.reload):
            (injectedExtensionAPI.InspectedWindow.prototype.evaluate):
            (injectedExtensionAPI.ExtensionServerClient.prototype.sendRequest):
            (injectedExtensionAPI.ExtensionServerClient.prototype.registerHandler):
            (injectedExtensionAPI.ExtensionServerClient.prototype.nextObjectId):
            (injectedExtensionAPI.ExtensionServerClient.prototype._registerCallback):
            (injectedExtensionAPI.ExtensionServerClient.prototype._onCallback):
            (injectedExtensionAPI.ExtensionServerClient.prototype._onMessage):
            (injectedExtensionAPI.expandURL):
            (injectedExtensionAPI.):
            * inspector/front-end/ExtensionPanel.js: Added. A class that provides WebInspector's Panel interface to the inspector, hosts extension panel within an IFrame and proxies Panel callbacks to the extension
    .
            (WebInspector.ExtensionPanel):
            (WebInspector.ExtensionPanel.prototype.get defaultFocusedElement):
            (WebInspector.ExtensionPanel.prototype.updateMainViewWidth):
            (WebInspector.ExtensionPanel.prototype.searchCanceled):
            (WebInspector.ExtensionPanel.prototype.performSearch):
            (WebInspector.ExtensionPanel.prototype.jumpToNextSearchResult):
            (WebInspector.ExtensionPanel.prototype.jumpToPreviousSearchResult):
            (WebInspector.ExtensionPanel.prototype._addStyleRule):
            * inspector/front-end/ExtensionRegistryStub.js: Added. A stub for ExtensionRegistry class that is meant to provide a list of extensions. Actual implementations may be browser-specfic.
            (.WebInspector.InspectorExtensionRegistryStub):
            (.WebInspector.InspectorExtensionRegistryStub.prototype.getExtensionsAsync):
            * inspector/front-end/ExtensionServer.js: Added. Communicates with ExtensionAPI via DOM messaging and proxies requests to WebInspector classes.
            (WebInspector.ExtensionServer):
            (WebInspector.ExtensionServer.prototype.notifyPanelShown):
            (WebInspector.ExtensionServer.prototype.notifyObjectSelected):
            (WebInspector.ExtensionServer.prototype.notifyResourceFinished):
            (WebInspector.ExtensionServer.prototype.notifySearchAction):
            (WebInspector.ExtensionServer.prototype.notifyInspectedPageLoaded):
            (WebInspector.ExtensionServer.prototype.notifyInspectedURLChanged):
            (WebInspector.ExtensionServer.prototype.notifyInspectorReset):
            (WebInspector.ExtensionServer.prototype._convertResource):
            (WebInspector.ExtensionServer.prototype._postNotification):
            (WebInspector.ExtensionServer.prototype._onSubscribe):
            (WebInspector.ExtensionServer.prototype._onUnsubscribe):
            (WebInspector.ExtensionServer.prototype._onCreatePanel):
            (WebInspector.ExtensionServer.prototype._onCreateSidebar):
            (WebInspector.ExtensionServer.prototype._createClientIframe):
            (WebInspector.ExtensionServer.prototype._onSetSidebarHeight):
            (WebInspector.ExtensionServer.prototype._onSetSidebarExpansion):
            (WebInspector.ExtensionServer.prototype._onLog):
            (WebInspector.ExtensionServer.prototype._onEvaluateOnInspectedPage):
            (WebInspector.ExtensionServer.prototype._onRevealAndSelect):
            (WebInspector.ExtensionServer.prototype._onRevealAndSelectResource):
            (WebInspector.ExtensionServer.prototype._dispatchCallback):
            (WebInspector.ExtensionServer.prototype._onGetResources):
            (WebInspector.ExtensionServer.prototype.initExtensions):
            (WebInspector.ExtensionServer.prototype._addExtensions):
            (WebInspector.ExtensionServer.prototype._onWindowMessage):
            (WebInspector.ExtensionServer.prototype._onmessage):
            (WebInspector.ExtensionServer.prototype._registerHandler):
            (WebInspector.ExtensionStatus):
            (WebInspector.addExtensions):
            * inspector/front-end/InjectedScript.js:
            (injectedScriptConstructor):
            * inspector/front-end/InjectedScriptAccess.js:
            * inspector/front-end/InspectorFrontendHostStub.js:
            (.WebInspector.InspectorFrontendHostStub.prototype.setExtensionAPI):
            (.WebInspector.InspectorFrontendHostStub.prototype.canAttachWindow):
            * inspector/front-end/WebKit.qrc:
            * inspector/front-end/inspector.html:
            * inspector/front-end/inspector.js:
            (WebInspector.loaded):
            (WebInspector.updateResource):
            (WebInspector.reset):
            (WebInspector.inspectedURLChanged):
            (WebInspector.didCommitLoad):
    
    2010-08-02  Andrey Kosyakov  <caseq at chromium.org>
    
            Reviewed by Pavel Feldman.
    
            Web Inspector: adding tests for WebInspector extensions API.
            https://bugs.webkit.org/show_bug.cgi?id=40425
    
            * http/tests/inspector/inspector-test.js:
            (dumpObject):
            * inspector/extensions-api-expected.txt: Added.
            * inspector/extensions-api.html: Added.
            * inspector/extensions-expected.txt: Added.
            * inspector/extensions-test.js: Added.
            (log):
            (frontend_initializeExtension):
            (doit):
            (done.callback):
            (done):
            (extensionFunctions):
            * inspector/extensions.html: Added.
            * inspector/resources/extension-main.html: Added.
            * inspector/resources/extension-main.js: Added.
            (fetchTests.callback):
            (fetchTests):
            (runTests):
            (onTestsDone):
            (runTest):
            (callbackAndNextTest.callbackWrapper):
            (callbackAndNextTest):
            (output):
            * inspector/resources/extension-panel.html: Added.
            * inspector/resources/extension-sidebar.html: Added.
            * platform/chromium/test_expectations.txt:
    
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64458 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index f778493..b881c57 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,37 @@
+2010-08-02  Andrey Kosyakov  <caseq at chromium.org>
+
+        Reviewed by Pavel Feldman.
+
+        Web Inspector: adding tests for WebInspector extensions API.
+        https://bugs.webkit.org/show_bug.cgi?id=40425
+
+        * http/tests/inspector/inspector-test.js:
+        (dumpObject):
+        * inspector/extensions-api-expected.txt: Added.
+        * inspector/extensions-api.html: Added.
+        * inspector/extensions-expected.txt: Added.
+        * inspector/extensions-test.js: Added.
+        (log):
+        (frontend_initializeExtension):
+        (doit):
+        (done.callback):
+        (done):
+        (extensionFunctions):
+        * inspector/extensions.html: Added.
+        * inspector/resources/extension-main.html: Added.
+        * inspector/resources/extension-main.js: Added.
+        (fetchTests.callback):
+        (fetchTests):
+        (runTests):
+        (onTestsDone):
+        (runTest):
+        (callbackAndNextTest.callbackWrapper):
+        (callbackAndNextTest):
+        (output):
+        * inspector/resources/extension-panel.html: Added.
+        * inspector/resources/extension-sidebar.html: Added.
+        * platform/chromium/test_expectations.txt:
+
 2010-08-02  Csaba Osztrogonác  <ossy at webkit.org>
 
         Unreviewed.
diff --git a/LayoutTests/http/tests/inspector/inspector-test.js b/LayoutTests/http/tests/inspector/inspector-test.js
index f412509..40ace31 100755
--- a/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/LayoutTests/http/tests/inspector/inspector-test.js
@@ -54,6 +54,8 @@ function dumpObject(object, nondeterministicProps, prefix, firstLinePrefix)
             dumpObject(propValue, nondeterministicProps, prefix + "    ", prefixWithName);
         else if (typeof propValue === "string")
             output(prefixWithName + "\"" + propValue + "\"");
+        else if (typeof propValue === "function")
+            output(prefixWithName + "<function>");
         else
             output(prefixWithName + propValue);
     }
diff --git a/LayoutTests/inspector/extensions-api-expected.txt b/LayoutTests/inspector/extensions-api-expected.txt
new file mode 100644
index 0000000..8f1a32d
--- /dev/null
+++ b/LayoutTests/inspector/extensions-api-expected.txt
@@ -0,0 +1,47 @@
+Tests public interface of WebInspector Extensions API
+
+Started extension.
+Running tests...
+RUNNING TEST: extension_testAPI
+{
+    inspectedWindow : {
+        onLoaded : {
+            addListener : <function>
+            removeListener : <function>
+        }
+        onNavigated : {
+            addListener : <function>
+            removeListener : <function>
+        }
+        onDOMContentLoaded : {
+            addListener : <function>
+            removeListener : <function>
+        }
+        reload : <function>
+        evaluate : <function>
+    }
+    panels : {
+        elements : {
+            createSidebarPane : <function>
+        }
+        scripts : {
+            createSidebarPane : <function>
+        }
+        create : <function>
+    }
+    resources : {
+        onFinished : {
+            addListener : <function>
+            removeListener : <function>
+        }
+        getAll : <function>
+        get : <function>
+    }
+    onReset : {
+        addListener : <function>
+        removeListener : <function>
+    }
+    log : <function>
+}
+All tests done.
+
diff --git a/LayoutTests/inspector/extensions-api.html b/LayoutTests/inspector/extensions-api.html
new file mode 100644
index 0000000..560cff7
--- /dev/null
+++ b/LayoutTests/inspector/extensions-api.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="extensions-test.js"></script>
+<script type="text/javascript">
+
+function extension_testAPI(nextTest)
+{
+    dumpObject(webInspector);
+    nextTest();
+}
+
+</script>
+</head>
+<body onload="onload()">
+<p>Tests public interface of WebInspector Extensions API</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/extensions-expected.txt b/LayoutTests/inspector/extensions-expected.txt
new file mode 100644
index 0000000..688c666
--- /dev/null
+++ b/LayoutTests/inspector/extensions-expected.txt
@@ -0,0 +1,34 @@
+Tests WebInspector extension API
+
+Started extension.
+Running tests...
+RUNNING TEST: extension_testCreatePanel
+done createPanel
+Panel created
+{
+    createSidebarPane : <function>
+    onSearch : {
+        addListener : <function>
+        removeListener : <function>
+    }
+}
+RUNNING TEST: extension_testCreateSidebar
+Sidebar created
+{
+    setHeight : <function>
+    setExpanded : <function>
+}
+RUNNING TEST: extension_testEvalFailed
+Evaluate: TypeError: JSON.stringify cannot serialize cyclic structures.(exception: true)
+RUNNING TEST: extension_testEvalOk
+Evaluate: {"str":"foo","num":42}(exception: undefined)
+RUNNING TEST: extension_testGetAllResources
+resource: .../tests/inspector/inspector-test.js
+resource: .../LayoutTests/inspector/extensions-test.js
+resource: .../LayoutTests/inspector/extensions.html
+RUNNING TEST: extension_testGetInvalidResource
+Attempted to retrieve invalid resource: {"code":"E_NOTFOUND","description":"Object not found (%s)","details":[2128506],"isError":true}
+RUNNING TEST: extension_testResourceNotification
+Resource finished: .../inspector/resources/extension-main.html
+All tests done.
+
diff --git a/LayoutTests/inspector/extensions-test.js b/LayoutTests/inspector/extensions-test.js
new file mode 100644
index 0000000..00d8ef5
--- /dev/null
+++ b/LayoutTests/inspector/extensions-test.js
@@ -0,0 +1,38 @@
+function log(message)
+{
+    output(message);
+}
+
+function frontend_initializeExtension(url)
+{
+    if (WebInspector.panels.resources.resourceTrackingEnabled)
+        WebInspector.addExtensions([{ startPage: url }]);
+    else
+        InspectorBackend.enableResourceTracking(false);
+}
+
+function doit()
+{
+    var extensionURL = location.href.replace(/\/[^/]*$/, "/resources/extension-main.html");
+    evaluateInWebInspector("frontend_initializeExtension('" + extensionURL + "')");
+}
+
+function done()
+{
+    function callback()
+    {
+        notifyDone();
+    }
+    evaluateInWebInspector("InspectorBackend.disableResourceTracking(false);", callback);
+}
+
+function extensionFunctions()
+{
+    var functions = "";
+
+    for (symbol in window) {
+        if (/^extension_/.exec(symbol) && typeof window[symbol] === "function")
+            functions += window[symbol].toString();
+    }
+    return functions;
+}
diff --git a/LayoutTests/inspector/extensions.html b/LayoutTests/inspector/extensions.html
new file mode 100644
index 0000000..63c682b
--- /dev/null
+++ b/LayoutTests/inspector/extensions.html
@@ -0,0 +1,87 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="extensions-test.js"></script>
+<script type="text/javascript">
+
+window.inspectedValue = { str: "foo", num: 42 };
+
+function extension_testEvalOk(nextTest)
+{
+    webInspector.inspectedWindow.evaluate("inspectedValue", callbackAndNextTest(extension_onEvaluate, nextTest));
+}
+
+function extension_testEvalFailed(nextTest)
+{
+    webInspector.inspectedWindow.evaluate("document.body", callbackAndNextTest(extension_onEvaluate, nextTest));
+}
+
+function extension_testGetAllResources(nextTest)
+{
+    function compareResources(a, b)
+    {
+        return a.har.request.url.localeCompare(b.har.request.url);
+    }
+
+    function onResource(result)
+    {
+        var resources = result.sort(compareResources);
+
+        for (var i = 0; i < resources.length; ++i)
+            log("resource: " + resources[i].har.request.url.replace(/.*((\/[^/]*){3}$)/,"...$1"));
+    }
+    webInspector.resources.getAll(callbackAndNextTest(onResource, nextTest));
+}
+
+function extension_testGetInvalidResource(nextTest)
+{
+    function onResource(result)
+    {
+        log("Attempted to retrieve invalid resource: " + JSON.stringify(result));
+    }
+    webInspector.resources.get(2128506, callbackAndNextTest(onResource, nextTest));
+}
+
+function extension_testCreatePanel(nextTest)
+{
+    function onPanelCreated(panel)
+    {
+        log("Panel created");
+        dumpObject(panel);
+    }
+    webInspector.panels.create("Test Panel", "extension-panel.html", "extension-panel.png", callbackAndNextTest(onPanelCreated, nextTest));
+    log("done createPanel");
+}
+
+function extension_testCreateSidebar(nextTest)
+{
+    function onSidebarCreated(sidebar)
+    {
+        log("Sidebar created");
+        dumpObject(sidebar);
+    }
+    webInspector.panels.scripts.createSidebarPane("Test Sidebar", "extension-sidebar.html", callbackAndNextTest(onSidebarCreated, nextTest));
+}
+
+function extension_testResourceNotification(nextTest)
+{
+    function onResourceFinished(resource)
+    {
+        log("Resource finished: " + resource.har.request.url.replace(/.*((\/[^/]*){3}$)/,"...$1"));
+    }
+
+    webInspector.resources.onFinished.addListener(callbackAndNextTest(onResourceFinished, nextTest));
+    webInspector.inspectedWindow.evaluate("var xhr = new XMLHttpRequest(); xhr.open('GET', '" + location.href + "', false); xhr.send(null);");
+}
+
+function extension_onEvaluate(result)
+{
+    log("Evaluate: " + result.value + "(exception: " + result.isException + ")");
+}
+
+</script>
+</head>
+<body onload="onload()">
+<p>Tests WebInspector extension API</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/resources/extension-main.html b/LayoutTests/inspector/resources/extension-main.html
new file mode 100644
index 0000000..e068e8f
--- /dev/null
+++ b/LayoutTests/inspector/resources/extension-main.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<script type="text/javascript">
+function log(message)
+{
+    webInspector.inspectedWindow.evaluate("log(unescape('" + escape(message) + "'));");
+}
+
+log("Started extension.");
+</script>
+
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="extension-main.js"></script>
+</head>
+</html>
diff --git a/LayoutTests/inspector/resources/extension-main.js b/LayoutTests/inspector/resources/extension-main.js
new file mode 100644
index 0000000..9bc6bb3
--- /dev/null
+++ b/LayoutTests/inspector/resources/extension-main.js
@@ -0,0 +1,66 @@
+function fetchTests()
+{
+    function callback(result)
+    {
+         var functions = JSON.parse(result.value);
+         window.eval(functions);
+         runTests();
+    }
+    webInspector.inspectedWindow.evaluate("extensionFunctions()", callback);
+}
+
+function runTests()
+{
+    log("Running tests...");
+    var tests = [];
+    for (var symbol in this) {
+        if (/^extension_test/.exec(symbol) && typeof this[symbol] === "function")
+            tests.push(symbol);
+    }
+    tests = tests.sort();
+    var testChain = onTestsDone;
+    for (var test = tests.pop(); test; test = tests.pop())
+        testChain = bind(runTest, this, bind(this[test], this, testChain), test);
+    testChain();
+}
+
+function onTestsDone()
+{
+    log("All tests done.");
+    webInspector.inspectedWindow.evaluate("done();");
+}
+
+function runTest(test, name)
+{
+    log("RUNNING TEST: " + name);
+    try {
+        test();
+    } catch (e) {
+        log(name + ": " + e);
+    }
+}
+
+function callbackAndNextTest(callback, nextTest)
+{
+    function callbackWrapper()
+    {
+        callback.apply(this, arguments);
+        nextTest.call(this);
+    }
+    return callbackWrapper;
+}
+
+function bind(func, thisObject)
+{
+    var args = Array.prototype.slice.call(arguments, 2);
+    return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))); };
+}
+
+// dumpObject() needs output(), so implement it via log().
+
+function output(msg)
+{
+    log(msg);
+}
+
+fetchTests();
diff --git a/LayoutTests/inspector/resources/extension-panel.html b/LayoutTests/inspector/resources/extension-panel.html
new file mode 100644
index 0000000..90531a4
--- /dev/null
+++ b/LayoutTests/inspector/resources/extension-panel.html
@@ -0,0 +1,2 @@
+<html>
+</html>
diff --git a/LayoutTests/inspector/resources/extension-sidebar.html b/LayoutTests/inspector/resources/extension-sidebar.html
new file mode 100644
index 0000000..90531a4
--- /dev/null
+++ b/LayoutTests/inspector/resources/extension-sidebar.html
@@ -0,0 +1,2 @@
+<html>
+</html>
diff --git a/LayoutTests/platform/chromium/test_expectations.txt b/LayoutTests/platform/chromium/test_expectations.txt
index e991bbc..2c90e6b 100644
--- a/LayoutTests/platform/chromium/test_expectations.txt
+++ b/LayoutTests/platform/chromium/test_expectations.txt
@@ -198,6 +198,7 @@ WONTFIX SKIP : fast/events/message-port-no-wrapper.html = FAIL
 WONTFIX SKIP : fast/events/message-port.html = FAIL
 WONTFIX SKIP : fast/events/message-port-multi.html = FAIL
 WONTFIX SKIP : http/tests/security/MessagePort/event-listener-context.html = FAIL
+WONTFIX SKIP : inspector/extensions.html = FAIL
 
 // Implement java testing harness.
 BUG36681 DEFER SKIP : java = TEXT
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 9cf734a..0c4e6ab 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,115 @@
+2010-08-02  Andrey Kosyakov  <caseq at chromium.org>
+
+        Reviewed by Pavel Feldman.
+
+        Web Inspector: adding experimental support for WebInspector extensions API.
+        https://bugs.webkit.org/show_bug.cgi?id=40425
+
+        Tests: inspector/extensions-api.html
+               inspector/extensions.html
+
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::inspectedWindowScriptObjectCleared):
+        (WebCore::InspectorController::didCommitLoad):
+        * inspector/InspectorFrontendHost.cpp:
+        (WebCore::InspectorFrontendHost::setExtensionAPI):
+        * inspector/InspectorFrontendHost.h:
+        * inspector/InspectorFrontendHost.idl:
+        * inspector/front-end/ElementsPanel.js:
+        (WebInspector.ElementsPanel.this.treeOutline.focusedNodeChanged):
+        (WebInspector.ElementsPanel):
+        * inspector/front-end/ExtensionAPI.js: Added. An API implementation that gets injected into the extension context.
+        (injectedExtensionAPI):
+        (injectedExtensionAPI.EventSinkImpl.prototype.addListener):
+        (injectedExtensionAPI.EventSinkImpl.prototype.removeListener):
+        (injectedExtensionAPI.EventSinkImpl.prototype._fire):
+        (injectedExtensionAPI.EventSink):
+        (injectedExtensionAPI.InspectorExtensionAPI):
+        (injectedExtensionAPI.InspectorExtensionAPI.prototype.log):
+        (injectedExtensionAPI.Resources.prototype.getAll):
+        (injectedExtensionAPI.Resources.prototype.get return):
+        (injectedExtensionAPI.Resources.prototype):
+        (injectedExtensionAPI.Panels):
+        (injectedExtensionAPI.Panels.prototype.create.callbackWrapper):
+        (injectedExtensionAPI.Panels.prototype.create):
+        (injectedExtensionAPI.PanelImpl):
+        (injectedExtensionAPI.PanelImpl.prototype.createSidebarPane.callbackWrapper):
+        (injectedExtensionAPI.PanelImpl.prototype.createSidebarPane):
+        (injectedExtensionAPI.ExtensionPanel):
+        (injectedExtensionAPI.ExtensionSidebarPaneImpl):
+        (injectedExtensionAPI.ExtensionSidebarPaneImpl.prototype.setHeight):
+        (injectedExtensionAPI.ExtensionSidebarPaneImpl.prototype.setExpanded):
+        (injectedExtensionAPI.InspectedWindow):
+        (injectedExtensionAPI.InspectedWindow.prototype.reload):
+        (injectedExtensionAPI.InspectedWindow.prototype.evaluate):
+        (injectedExtensionAPI.ExtensionServerClient.prototype.sendRequest):
+        (injectedExtensionAPI.ExtensionServerClient.prototype.registerHandler):
+        (injectedExtensionAPI.ExtensionServerClient.prototype.nextObjectId):
+        (injectedExtensionAPI.ExtensionServerClient.prototype._registerCallback):
+        (injectedExtensionAPI.ExtensionServerClient.prototype._onCallback):
+        (injectedExtensionAPI.ExtensionServerClient.prototype._onMessage):
+        (injectedExtensionAPI.expandURL):
+        (injectedExtensionAPI.):
+        * inspector/front-end/ExtensionPanel.js: Added. A class that provides WebInspector's Panel interface to the inspector, hosts extension panel within an IFrame and proxies Panel callbacks to the extension.
+        (WebInspector.ExtensionPanel):
+        (WebInspector.ExtensionPanel.prototype.get defaultFocusedElement):
+        (WebInspector.ExtensionPanel.prototype.updateMainViewWidth):
+        (WebInspector.ExtensionPanel.prototype.searchCanceled):
+        (WebInspector.ExtensionPanel.prototype.performSearch):
+        (WebInspector.ExtensionPanel.prototype.jumpToNextSearchResult):
+        (WebInspector.ExtensionPanel.prototype.jumpToPreviousSearchResult):
+        (WebInspector.ExtensionPanel.prototype._addStyleRule):
+        * inspector/front-end/ExtensionRegistryStub.js: Added. A stub for ExtensionRegistry class that is meant to provide a list of extensions. Actual implementations may be browser-specfic.
+        (.WebInspector.InspectorExtensionRegistryStub):
+        (.WebInspector.InspectorExtensionRegistryStub.prototype.getExtensionsAsync):
+        * inspector/front-end/ExtensionServer.js: Added. Communicates with ExtensionAPI via DOM messaging and proxies requests to WebInspector classes.
+        (WebInspector.ExtensionServer):
+        (WebInspector.ExtensionServer.prototype.notifyPanelShown):
+        (WebInspector.ExtensionServer.prototype.notifyObjectSelected):
+        (WebInspector.ExtensionServer.prototype.notifyResourceFinished):
+        (WebInspector.ExtensionServer.prototype.notifySearchAction):
+        (WebInspector.ExtensionServer.prototype.notifyInspectedPageLoaded):
+        (WebInspector.ExtensionServer.prototype.notifyInspectedURLChanged):
+        (WebInspector.ExtensionServer.prototype.notifyInspectorReset):
+        (WebInspector.ExtensionServer.prototype._convertResource):
+        (WebInspector.ExtensionServer.prototype._postNotification):
+        (WebInspector.ExtensionServer.prototype._onSubscribe):
+        (WebInspector.ExtensionServer.prototype._onUnsubscribe):
+        (WebInspector.ExtensionServer.prototype._onCreatePanel):
+        (WebInspector.ExtensionServer.prototype._onCreateSidebar):
+        (WebInspector.ExtensionServer.prototype._createClientIframe):
+        (WebInspector.ExtensionServer.prototype._onSetSidebarHeight):
+        (WebInspector.ExtensionServer.prototype._onSetSidebarExpansion):
+        (WebInspector.ExtensionServer.prototype._onLog):
+        (WebInspector.ExtensionServer.prototype._onEvaluateOnInspectedPage):
+        (WebInspector.ExtensionServer.prototype._onRevealAndSelect):
+        (WebInspector.ExtensionServer.prototype._onRevealAndSelectResource):
+        (WebInspector.ExtensionServer.prototype._dispatchCallback):
+        (WebInspector.ExtensionServer.prototype._onGetResources):
+        (WebInspector.ExtensionServer.prototype.initExtensions):
+        (WebInspector.ExtensionServer.prototype._addExtensions):
+        (WebInspector.ExtensionServer.prototype._onWindowMessage):
+        (WebInspector.ExtensionServer.prototype._onmessage):
+        (WebInspector.ExtensionServer.prototype._registerHandler):
+        (WebInspector.ExtensionStatus):
+        (WebInspector.addExtensions):
+        * inspector/front-end/InjectedScript.js:
+        (injectedScriptConstructor):
+        * inspector/front-end/InjectedScriptAccess.js:
+        * inspector/front-end/InspectorFrontendHostStub.js:
+        (.WebInspector.InspectorFrontendHostStub.prototype.setExtensionAPI):
+        (.WebInspector.InspectorFrontendHostStub.prototype.canAttachWindow):
+        * inspector/front-end/WebKit.qrc:
+        * inspector/front-end/inspector.html:
+        * inspector/front-end/inspector.js:
+        (WebInspector.loaded):
+        (WebInspector.updateResource):
+        (WebInspector.reset):
+        (WebInspector.inspectedURLChanged):
+        (WebInspector.didCommitLoad):
+
 2010-08-02  Ilya Tikhonovsky  <loislo at chromium.org>
 
         Reviewed by Yury Semikhatsky.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index 7bbffe2..20482bb 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -4055,6 +4055,10 @@
             'inspector/front-end/ElementsPanel.js',
             'inspector/front-end/ElementsTreeOutline.js',
             'inspector/front-end/EventListenersSidebarPane.js',
+            'inspector/front-end/ExtensionAPI.js',
+            'inspector/front-end/ExtensionPanel.js',
+            'inspector/front-end/ExtensionRegistryStub.js',
+            'inspector/front-end/ExtensionServer.js',
             'inspector/front-end/FontView.js',
             'inspector/front-end/HAREntry.js',
             'inspector/front-end/HelpScreen.js',
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 817746f..32220a0 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -50912,6 +50912,22 @@
 					>
 				</File>
 				<File
+					RelativePath="..\inspector\front-end\ExtensionAPI.js"
+					>
+				</File>
+				<File
+					RelativePath="..\inspector\front-end\ExtensionPanel.js"
+					>
+				</File>
+				<File
+					RelativePath="..\inspector\front-end\ExtensionRegistryStub.js"
+					>
+				</File>
+				<File
+					RelativePath="..\inspector\front-end\ExtensionServer.js"
+					>
+				</File>
+				<File
 					RelativePath="..\inspector\front-end\FontView.js"
 					>
 				</File>
diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp
index e29c7ae..369b40b 100644
--- a/WebCore/inspector/InspectorController.cpp
+++ b/WebCore/inspector/InspectorController.cpp
@@ -458,9 +458,18 @@ void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
     if (m_inspectorFrontendClient && frame == m_inspectedPage->mainFrame())
         m_inspectorFrontendClient->windowObjectCleared();
 
-    if (!enabled() || !m_frontend || frame != m_inspectedPage->mainFrame())
+    if (!enabled())
         return;
-    m_injectedScriptHost->discardInjectedScripts();
+
+    if (m_frontend && frame != m_inspectedPage->mainFrame())
+        m_injectedScriptHost->discardInjectedScripts();
+    if (m_scriptsToEvaluateOnLoad.size()) {
+        ScriptState* scriptState = mainWorldScriptState(frame);
+        for (Vector<String>::iterator it = m_scriptsToEvaluateOnLoad.begin();
+             it != m_scriptsToEvaluateOnLoad.end(); ++it) {
+            m_injectedScriptHost->injectScript(*it, scriptState);
+        }
+    }
 }
 
 void InspectorController::setSearchingForNode(bool enabled)
@@ -802,14 +811,6 @@ void InspectorController::didCommitLoad(DocumentLoader* loader)
     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
             pruneResources(resourceMap, loader);
-
-    if (m_scriptsToEvaluateOnLoad.size()) {
-        ScriptState* scriptState = mainWorldScriptState(loader->frame());
-        for (Vector<String>::iterator it = m_scriptsToEvaluateOnLoad.begin();
-             it != m_scriptsToEvaluateOnLoad.end(); ++it) {
-            m_injectedScriptHost->injectScript(*it, scriptState);
-        }
-    }
 }
 
 void InspectorController::frameDetachedFromParent(Frame* frame)
diff --git a/WebCore/inspector/InspectorFrontendHost.cpp b/WebCore/inspector/InspectorFrontendHost.cpp
index 6957dd1..0dacde6 100644
--- a/WebCore/inspector/InspectorFrontendHost.cpp
+++ b/WebCore/inspector/InspectorFrontendHost.cpp
@@ -192,6 +192,14 @@ void InspectorFrontendHost::moveWindowBy(float x, float y) const
         m_client->moveWindowBy(x, y);
 }
 
+void InspectorFrontendHost::setExtensionAPI(const String& script)
+{
+    InspectorController* inspector = m_frontendPage->inspectorController();
+
+    inspector->removeAllScriptsToEvaluateOnLoad();
+    inspector->addScriptToEvaluateOnLoad(script);
+}
+
 String InspectorFrontendHost::localizedStringsURL()
 {
     return m_client->localizedStringsURL();
diff --git a/WebCore/inspector/InspectorFrontendHost.h b/WebCore/inspector/InspectorFrontendHost.h
index 7fb4a1e..4b343fd 100644
--- a/WebCore/inspector/InspectorFrontendHost.h
+++ b/WebCore/inspector/InspectorFrontendHost.h
@@ -67,6 +67,7 @@ public:
 
     void setAttachedWindowHeight(unsigned height);
     void moveWindowBy(float x, float y) const;
+    void setExtensionAPI(const String& script);
 
     String localizedStringsURL();
     String hiddenPanels();
diff --git a/WebCore/inspector/InspectorFrontendHost.idl b/WebCore/inspector/InspectorFrontendHost.idl
index d1b3604..0c7cf8b 100644
--- a/WebCore/inspector/InspectorFrontendHost.idl
+++ b/WebCore/inspector/InspectorFrontendHost.idl
@@ -41,6 +41,7 @@ module core {
         void requestDetachWindow();
         void setAttachedWindowHeight(in unsigned long height);
         void moveWindowBy(in float x, in float y);
+        void setExtensionAPI(in DOMString script);
 
         DOMString localizedStringsURL();
         DOMString hiddenPanels();
diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js
index 557a8bd..09a84f7 100644
--- a/WebCore/inspector/front-end/ElementsPanel.js
+++ b/WebCore/inspector/front-end/ElementsPanel.js
@@ -56,8 +56,10 @@ WebInspector.ElementsPanel = function()
         this.panel.updateProperties();
         this.panel.updateEventListeners();
 
-        if (this._focusedDOMNode)
+        if (this._focusedDOMNode) {
             InspectorBackend.addInspectedNode(this._focusedDOMNode.id);
+            WebInspector.extensionServer.notifyObjectSelected(this.name, "DOMNode");
+        }
     };
 
     this.contentElement.appendChild(this.treeOutline.element);
diff --git a/WebCore/inspector/front-end/ExtensionAPI.js b/WebCore/inspector/front-end/ExtensionAPI.js
new file mode 100644
index 0000000..476a463
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionAPI.js
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
+{
+
+// Here and below, all constructors are private to API implementation.
+// For a public type Foo, if internal fields are present, these are on
+// a private FooImpl type, an instance of FooImpl is used in a closure
+// by Foo consutrctor to re-bind publicly exported members to an instance
+// of Foo.
+
+function EventSinkImpl(type)
+{
+    this._type = type;
+    this._listeners = [];
+}
+
+EventSinkImpl.prototype = {
+    addListener: function(callback)
+    {
+        if (this._listeners.length === 0)
+            extensionServer.sendRequest({ command: "subscribe", type: this._type });
+        this._listeners.push(callback);
+        extensionServer.registerHandler("notify-" + this._type, bind(this._fire, this));
+    },
+
+    removeListener: function(callback)
+    {
+        var listeners = this._listeners;
+
+        for (var i = 0; i < listeners.length; ++i) {
+            if (listeners[i] === callback) {
+                listeners.splice(i, 1);
+                break;
+            }
+        }
+        if (this._listeners.length === 0)
+            extensionServer.sendRequest({ command: "unsubscribe", type: this._type });
+    },
+
+    _fire: function(request)
+    {
+        var listeners = this._listeners.slice();
+        for (var i = 0; i < listeners.length; ++i)
+            listeners[i].apply(null, request.arguments);
+    }
+}
+
+function EventSink(type)
+{
+    var impl = new EventSinkImpl(type);
+    this.addListener = bind(impl.addListener, impl);
+    this.removeListener = bind(impl.removeListener, impl);
+}
+
+function InspectorExtensionAPI()
+{
+    this.inspectedWindow = new InspectedWindow();
+    this.panels = new Panels();
+    this.resources = new Resources();
+    this.onReset = new EventSink("reset");
+}
+
+InspectorExtensionAPI.prototype = {
+    log: function(message)
+    {
+        extensionServer.sendRequest({ command: "log", message: message });
+    }
+}
+
+function Resources()
+{
+    this.onFinished = new EventSink("resource-finished");
+}
+
+Resources.prototype = {
+    getAll: function(callback)
+    {
+        return extensionServer.sendRequest({ command: "getResources" }, callback);
+    },
+
+    get: function(id, callback)
+    {
+        return extensionServer.sendRequest({ command: "getResources", id: id }, callback);
+    }
+}
+
+var wellKnownPanelNames = [
+    "elements",
+    "scripts"
+];
+
+function Panels()
+{
+    var panels = [];
+    function panelGetter(name)
+    {
+        return panels[name];
+    }
+    
+    for (var i = 0; i < wellKnownPanelNames.length; ++i) {
+        var name = wellKnownPanelNames[i];
+        panels[name] = new Panel(name);
+        this.__defineGetter__(name, bind(panelGetter, null, name));
+    }
+}
+
+Panels.prototype = {
+    create: function(label, pageURL, iconURL, callback)
+    {
+        var id = "extension-panel-" + extensionServer.nextObjectId();
+        function callbackWrapper(result)
+        {
+            if (result.isError)
+                callback(result);
+            else {
+                panel = new ExtensionPanel(id);
+                callback(panel);
+            }
+        }
+        var request = {
+            command: "createPanel",
+            id: id,
+            label: label,
+            url: expandURL(pageURL),
+            icon: expandURL(iconURL) 
+        };
+        extensionServer.sendRequest(request, callback && bind(callbackWrapper, this));
+    }
+}
+
+function PanelImpl(id)
+{
+    this._id = id;
+    this.onSelectionChanged = new EventSink("panel-objectSelected-" + id);
+}
+
+PanelImpl.prototype = {
+    createSidebarPane: function(title, url, callback)
+    {
+        var id = "extension-sidebar-" + extensionServer.nextObjectId();
+        function callbackWrapper(result)
+        {
+            if (result.isError)
+                callback(result);
+            else
+                callback(new ExtensionSidebarPane(id));
+        }
+        extensionServer.sendRequest({ command: "createSidebarPane", panel: this._id, id: id, title: title, url: expandURL(url) }, callback && callbackWrapper);
+    }
+}
+
+function Panel(id)
+{
+    var impl = new PanelImpl(id);
+    this.createSidebarPane = bind(impl.createSidebarPane, impl);
+}
+
+function ExtensionPanel(id)
+{
+    Panel.call(this, id);
+    this.onSearch = new EventSink("panel-search-" + id);
+}
+
+ExtensionPanel.prototype = {
+}
+
+ExtensionPanel.prototype.__proto__ = Panel.prototype;
+
+function ExtensionSidebarPaneImpl(id)
+{
+    this._id = id;
+}
+
+ExtensionSidebarPaneImpl.prototype = {
+    setHeight: function(height)
+    {
+        extensionServer.sendRequest({ command: "setSidebarHeight", id: this._id, height: height });
+    },
+
+    setExpanded: function(expanded)
+    {
+        extensionServer.sendRequest({ command: "setSidebarExpanded", id: this._id, expanded: expanded });
+    }
+}
+
+function ExtensionSidebarPane(id)
+{
+    var impl = new ExtensionSidebarPaneImpl(id);
+    this.setHeight = bind(impl.setHeight, impl);
+    this.setExpanded = bind(impl.setExpanded, impl);
+}
+
+function InspectedWindow()
+{
+    this.onLoaded = new EventSink("inspectedPageLoaded");
+    this.onNavigated = new EventSink("inspectedURLChanged");
+    this.onDOMContentLoaded = new EventSink("DOMContentLoaded");
+}
+
+InspectedWindow.prototype = {
+    reload: function()
+    {
+        return extensionServer.sendRequest({ command: "reload" });
+    },
+
+    evaluate: function(expression, callback)
+    {
+        return extensionServer.sendRequest({ command: "evaluateOnInspectedPage", expression: expression }, callback);
+    }
+}
+
+function ExtensionServerClient()
+{
+    this._callbacks = {};
+    this._handlers = {};
+    this._lastRequestId = 0;
+    this._lastObjectId = 0;
+
+    this.registerHandler("callback", bind(this._onCallback, this));
+
+    var channel = new MessageChannel();
+    this._port = channel.port1;
+    this._port.addEventListener("message", bind(this._onMessage, this), false);
+    this._port.start();
+
+    top.postMessage("registerExtension", [ channel.port2 ], "*");
+}
+
+ExtensionServerClient.prototype = {
+    sendRequest: function(message, callback)
+    {
+        if (typeof callback === "function")
+            message.requestId = this._registerCallback(callback);
+        return this._port.postMessage(message);
+    },
+
+    registerHandler: function(command, handler)
+    {
+        this._handlers[command] = handler;
+    },
+
+    nextObjectId: function()
+    {
+        return injectedScriptId + "_" + ++this._lastObjectId;
+    },
+
+    _registerCallback: function(callback)
+    {
+        var id = ++this._lastRequestId;
+        this._callbacks[id] = callback;
+        return id;
+    },
+
+    _onCallback: function(request)
+    {
+        if (request.requestId in this._callbacks) {
+            this._callbacks[request.requestId](request.result);
+            delete this._callbacks[request.requestId];
+        }
+    },
+
+    _onMessage: function(event)
+    {
+        var request = event.data;
+        var handler = this._handlers[request.command];
+        if (handler)
+            handler.call(this, request);
+    }
+}
+
+function expandURL(url)
+{
+    if (!url)
+        return url;
+    if (/^[^/]+:/.exec(url)) // See if url has schema.
+        return url;
+    var baseURL = location.protocol + "//" + location.hostname + location.port;
+    if (/^\//.exec(url))
+        return baseURL + url;
+    return baseURL + location.pathname.replace(/\/[^/]*$/,"/") + url;
+}
+
+function bind(func, thisObject)
+{
+    var args = Array.prototype.slice.call(arguments, 2);
+    return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))); };
+}
+
+var extensionServer = new ExtensionServerClient();
+
+webInspector = new InspectorExtensionAPI();
+
+}
diff --git a/WebCore/inspector/front-end/ExtensionPanel.js b/WebCore/inspector/front-end/ExtensionPanel.js
new file mode 100644
index 0000000..ba5fa8e
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionPanel.js
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+WebInspector.ExtensionPanel = function(id, label, iconURL, options)
+{
+    this.toolbarItemLabel = label;
+    this._addStyleRule(".toolbar-item." + id + " .toolbar-icon", "background-image: url(" + iconURL + ");");
+    WebInspector.Panel.call(this, id);
+}
+
+WebInspector.ExtensionPanel.prototype = {
+    get defaultFocusedElement()
+    {
+        return this.sidebarTreeElement || this.element;
+    },
+
+    updateMainViewWidth: function(width)
+    {
+        this.bodyElement.style.left = width + "px";
+        this.resize();
+    },
+
+    searchCanceled: function(startingNewSearch)
+    {
+        WebInspector.extensionServer.notifySearchAction(this._id, "cancelSearch");
+        WebInspector.Panel.prototype.searchCanceled.apply(this, arguments);
+    },
+
+    performSearch: function(query)
+    {
+        WebInspector.extensionServer.notifySearchAction(this._id, "performSearch", query);
+        WebInspector.Panel.prototype.performSearch.apply(this, arguments);
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        WebInspector.extensionServer.notifySearchAction(this._id, "nextSearchResult");
+        WebInspector.Panel.prototype.jumpToNextSearchResult.call(this);
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        WebInspector.extensionServer.notifySearchAction(this._id, "previousSearchResult");
+        WebInspector.Panel.prototype.jumpToPreviousSearchResult.call(this);
+    },
+
+    _addStyleRule: function(selector, body)
+    {
+        var style = document.createElement("style");
+        style.textContent = selector + " { " + body + " }";
+        document.head.appendChild(style);
+    }
+}
+
+WebInspector.ExtensionPanel.prototype.__proto__ = WebInspector.Panel.prototype;
diff --git a/WebCore/inspector/front-end/ExtensionRegistryStub.js b/WebCore/inspector/front-end/ExtensionRegistryStub.js
new file mode 100644
index 0000000..a9c96ef
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionRegistryStub.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+if (!window.InspectorExtensionRegistry) {
+
+WebInspector.InspectorExtensionRegistryStub = function()
+{
+}
+
+WebInspector.InspectorExtensionRegistryStub.prototype = {
+    getExtensionsAsync: function()
+    {
+    }
+};
+
+InspectorExtensionRegistry = new WebInspector.InspectorExtensionRegistryStub();
+
+}
diff --git a/WebCore/inspector/front-end/ExtensionServer.js b/WebCore/inspector/front-end/ExtensionServer.js
new file mode 100644
index 0000000..2d2eab1
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionServer.js
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+WebInspector.ExtensionServer = function()
+{
+    this._clientObjects = {};
+    this._handlers = {};
+    this._subscribers = {};
+    this._status = new WebInspector.ExtensionStatus();
+
+    this._registerHandler("subscribe", this._onSubscribe.bind(this));
+    this._registerHandler("unsubscribe", this._onUnsubscribe.bind(this));
+    this._registerHandler("getResources", this._onGetResources.bind(this));
+    this._registerHandler("createPanel", this._onCreatePanel.bind(this));
+    this._registerHandler("createSidebarPane", this._onCreateSidebar.bind(this));
+    this._registerHandler("log", this._onLog.bind(this)); 
+    this._registerHandler("evaluateOnInspectedPage", this._onEvaluateOnInspectedPage.bind(this));
+    this._registerHandler("setSidebarHeight", this._onSetSidebarHeight.bind(this));
+    this._registerHandler("setSidebarExpanded", this._onSetSidebarExpansion.bind(this));
+
+    window.addEventListener("message", this._onWindowMessage.bind(this), false);
+}
+
+WebInspector.ExtensionServer.prototype = {
+    notifyPanelShown: function(panelName)
+    {
+        this._postNotification("panel-shown-" + panelName);
+    },
+
+    notifyObjectSelected: function(panelId, objectType, objectId)
+    {
+        this._postNotification("panel-objectSelected-" + panelId, objectType, objectId);
+    },
+
+    notifyResourceFinished: function(resource)
+    {
+        this._postNotification("resource-finished", this._convertResource(resource));
+    },
+
+    notifySearchAction: function(panelId, action, searchString)
+    {
+        this._postNotification("panel-search-" + panelId, action, searchString);
+    },
+
+    notifyInspectedPageLoaded: function()
+    {
+        this._postNotification("inspectedPageLoaded");
+    },
+
+    notifyInspectedURLChanged: function()
+    {
+        this._postNotification("inspectedURLChanged");
+    },
+
+    notifyInspectorReset: function()
+    {
+        this._postNotification("reset");
+    },
+
+    _convertResource: function(resource)
+    {
+        return {
+            id: resource.identifier,
+            type: resource.type,
+            har: (new WebInspector.HAREntry(resource)).build(),
+        };
+    },
+
+    _postNotification: function(type, details)
+    {
+        var subscribers = this._subscribers[type];
+        if (!subscribers)
+            return;
+        var message = {
+            command: "notify-" + type,
+            arguments: Array.prototype.slice.call(arguments, 1) 
+        };
+        for (var i = 0; i < subscribers.length; ++i)
+            subscribers[i].postMessage(message);
+    },
+
+    _onSubscribe: function(message, port)
+    {
+        var subscribers = this._subscribers[message.type];
+        if (subscribers)
+            subscribers.push(port);
+        else
+            this._subscribers[message.type] = [ port ];
+    },
+
+    _onUnsubscribe: function(message, port)
+    {
+        var subscribers = this._subscribers[message.type];
+        if (!subscribers)
+            return;
+        subscribers.remove(port);
+        if (!subscribers.length)
+            delete this._subscribers[message.type];
+    },
+
+    _onCreatePanel: function(message, port)
+    {
+        var id = message.id;
+        // The ids are generated on the client API side and must be unique, so the check below
+        // shouldn't be hit unless someone is bypassing the API.
+        if (id in this._clientObjects || id in WebInspector.panels)
+            return this._status.E_EXISTS(id);
+        var panel = new WebInspector.ExtensionPanel(id, message.label, message.icon);
+        this._clientObjects[id] = panel;
+
+        var toolbarElement = document.getElementById("toolbar");
+        var lastToolbarItem = WebInspector.panelOrder[WebInspector.panelOrder.length - 1].toolbarItem;
+        WebInspector.addPanelToolbarIcon(toolbarElement, panel, lastToolbarItem);
+        WebInspector.panels[id] = panel;
+        this._createClientIframe(panel.element, message.url);
+        return this._status.OK();
+    },
+
+    _onCreateSidebar: function(message, port)
+    {
+        var panel = WebInspector.panels[message.panel];
+        if (!panel)
+            return this._status.E_NOTFOUND(message.panel);
+        if (!panel.sidebarElement || !panel.sidebarPanes)
+            return this._status.E_NOTSUPPORTED();
+        var id = message.id;
+        var sidebar = new WebInspector.SidebarPane(message.title);
+        this._clientObjects[id] = sidebar;
+        panel.sidebarPanes[id] = sidebar;
+        panel.sidebarElement.appendChild(sidebar.element);
+        this._createClientIframe(sidebar.bodyElement, message.url);
+        return this._status.OK();
+    },
+
+    _createClientIframe: function(parent, url, requestId, port)
+    {
+        var iframe = document.createElement("iframe");
+        iframe.src = url;
+        iframe.style.width = "100%";
+        parent.appendChild(iframe);
+    },
+
+    _onSetSidebarHeight: function(message)
+    {
+        var sidebar = this._clientObjects[message.id];
+        if (!sidebar)
+            return this._status.E_NOTFOUND(message.id);
+        sidebar.bodyElement.firstChild.style.height = message.height;
+    },
+
+    _onSetSidebarExpansion: function(message)
+    {
+        var sidebar = this._clientObjects[message.id];
+        if (!sidebar)
+            return this._status.E_NOTFOUND(message.id);
+        if (message.expanded)
+            sidebar.expand();
+        else
+            sidebar.collapse();
+    },
+
+    _onLog: function(message)
+    {
+        WebInspector.log(message.message);
+    },
+
+    _onEvaluateOnInspectedPage: function(message, port)
+    {
+        InjectedScriptAccess.getDefault().evaluateAndStringify(message.expression, this._dispatchCallback.bind(this, message.requestId, port));
+    },
+
+    _onRevealAndSelect: function(message)
+    {
+        if (message.panelId === "resources" && type === "resource")
+            return this._onRevealAndSelectResource(message);
+        else
+            return this._status.E_NOTSUPPORTED(message.panelId, message.type);
+    },
+
+    _onRevealAndSelectResource: function(message)
+    {
+        var id = message.id;
+        var resource = null;
+
+        resource = typeof id === "number" ? WebInspector.resources[id] : WebInspector.resourceForURL(id);
+        if (!resource)
+            return this._status.E_NOTFOUND(typeof id + ": " + id);
+        WebInspector.panels.resources.showResource(resource, message.line);
+        WebInspector.showResourcesPanel();
+    },
+
+    _dispatchCallback: function(requestId, port, result)
+    {
+        port.postMessage({ command: "callback", requestId: requestId, result: result });
+    },
+
+    _onGetResources: function(request)
+    {
+        function resourceWrapper(id)
+        {
+            return WebInspector.extensionServer._convertResource(WebInspector.resources[id]);
+        }
+
+        var response;
+        if (request.id)
+            response = WebInspector.resources[request.id] ? resourceWrapper(request.id) : this._status.E_NOTFOUND(request.id);
+        else
+            response = Object.properties(WebInspector.resources).map(resourceWrapper);
+        return response;
+    },
+
+    initExtensions: function()
+    {
+        InspectorExtensionRegistry.getExtensionsAsync();
+    },
+
+    _addExtensions: function(extensions)
+    {
+        InspectorFrontendHost.setExtensionAPI("(" + injectedExtensionAPI.toString() + ")"); // See ExtensionAPI.js for details.
+        for (var i = 0; i < extensions.length; ++i) {
+            var extension = extensions[i];
+            try {
+                if (!extension.startPage)
+                    return;
+                var iframe = document.createElement("iframe");
+                iframe.src = extension.startPage;
+                iframe.style.display = "none";
+                document.body.appendChild(iframe);
+            } catch (e) {
+                console.error("Failed to initialize extension " + extension.startPage + ":" + e);
+            }
+        }
+    },
+
+    _onWindowMessage: function(event)
+    {
+        if (event.data !== "registerExtension")
+            return;
+        var port = event.ports[0];
+        port.addEventListener("message", this._onmessage.bind(this), false);
+        port.start();
+    },
+
+    _onmessage: function(event)
+    {
+        var request = event.data;
+        var result;
+
+        if (request.command in this._handlers)
+            result = this._handlers[request.command](request, event.target);
+        else
+            result = this._status.E_NOTSUPPORTED(request.command);
+
+        if (result && request.requestId)
+            this._dispatchCallback(request.requestId, event.target, result);
+    },
+
+    _registerHandler: function(command, callback)
+    {
+        this._handlers[command] = callback;
+    }
+}
+
+WebInspector.ExtensionServer._statuses = 
+{
+    OK: "",
+    E_NOTFOUND: "Object not found (%s)",
+    E_NOTSUPPORTED: "Object does not support requested operation (%s)",
+    E_EXISTS: "Object already exists (%s)"
+}
+
+WebInspector.ExtensionStatus = function()
+{
+    function makeStatus(code)
+    {
+        var description = WebInspector.ExtensionServer._statuses[code] || code;
+        var details = Array.prototype.slice.call(arguments, 1);
+        var status = { code: code, description: description, details: details };
+        if (code !== "OK") {
+            status.isError = true;
+            console.log("Extension server error: " + String.vsprintf(description, details));
+        }
+        return status; 
+    }
+    for (status in WebInspector.ExtensionServer._statuses)
+        this[status] = makeStatus.bind(null, status);
+}
+
+WebInspector.addExtensions = function(extensions)
+{
+    WebInspector.extensionServer._addExtensions(extensions);
+}
diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js
index ce187d2..3a114c0 100644
--- a/WebCore/inspector/front-end/InjectedScript.js
+++ b/WebCore/inspector/front-end/InjectedScript.js
@@ -238,6 +238,19 @@ InjectedScript.getCompletions = function(expression, includeInspectorCommandLine
     return props;
 }
 
+InjectedScript.evaluateAndStringify = function(expression)
+{
+    var result = {};
+    try {
+        var value = InjectedScript._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false);
+        result.value = JSON.stringify(value);
+    } catch (e) {
+        result.value = e.toString();
+        result.isException = true;
+    }
+    return result;
+}
+
 InjectedScript.evaluate = function(expression, objectGroup)
 {
     return InjectedScript._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup);
diff --git a/WebCore/inspector/front-end/InjectedScriptAccess.js b/WebCore/inspector/front-end/InjectedScriptAccess.js
index 5950421..59aa70c 100644
--- a/WebCore/inspector/front-end/InjectedScriptAccess.js
+++ b/WebCore/inspector/front-end/InjectedScriptAccess.js
@@ -75,14 +75,15 @@ InjectedScriptAccess._installHandler = function(methodName, async)
 // - Make sure last parameter of all the InjectedSriptAccess.* calls is a callback function.
 // We keep these sorted.
 InjectedScriptAccess._installHandler("evaluate");
+InjectedScriptAccess._installHandler("evaluateAndStringify");
 InjectedScriptAccess._installHandler("evaluateInCallFrame");
+InjectedScriptAccess._installHandler("evaluateOnSelf");
 InjectedScriptAccess._installHandler("getCompletions");
 InjectedScriptAccess._installHandler("getProperties");
 InjectedScriptAccess._installHandler("getPrototypes");
 InjectedScriptAccess._installHandler("openInInspectedWindow");
 InjectedScriptAccess._installHandler("pushNodeToFrontend");
 InjectedScriptAccess._installHandler("setPropertyValue");
-InjectedScriptAccess._installHandler("evaluateOnSelf");
 
 // Some methods can't run synchronously even on the injected script side (such as DB transactions).
 // Mark them as asynchronous here.
diff --git a/WebCore/inspector/front-end/InspectorFrontendHostStub.js b/WebCore/inspector/front-end/InspectorFrontendHostStub.js
index c771967..c4e6bf4 100644
--- a/WebCore/inspector/front-end/InspectorFrontendHostStub.js
+++ b/WebCore/inspector/front-end/InspectorFrontendHostStub.js
@@ -84,6 +84,10 @@ WebInspector.InspectorFrontendHostStub.prototype = {
     {
     },
 
+    setExtensionAPI: function(script)
+    {
+    },
+
     loaded: function()
     {
     },
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index 42ad915..a54936c 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -34,6 +34,10 @@
     <file>ElementsPanel.js</file>
     <file>ElementsTreeOutline.js</file>
     <file>EventListenersSidebarPane.js</file>
+    <file>ExtensionAPI.js</file>
+    <file>ExtensionPanel.js</file>
+    <file>ExtensionRegistryStub.js</file>
+    <file>ExtensionServer.js</file>
     <file>FontView.js</file>
     <file>HAREntry.js</file>
     <file>HelpScreen.js</file>
diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
index c829195..48e95bb 100644
--- a/WebCore/inspector/front-end/inspector.html
+++ b/WebCore/inspector/front-end/inspector.html
@@ -39,6 +39,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="inspector.js"></script>
     <script type="text/javascript" src="InspectorBackendStub.js"></script>
     <script type="text/javascript" src="InspectorFrontendHostStub.js"></script>
+    <script type="text/javascript" src="ExtensionRegistryStub.js"></script>
     <script type="text/javascript" src="Object.js"></script>
     <script type="text/javascript" src="Settings.js"></script>
     <script type="text/javascript" src="CSSStyleModel.js"></script>
@@ -96,6 +97,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="StoragePanel.js"></script>
     <script type="text/javascript" src="ProfilesPanel.js"></script>
     <script type="text/javascript" src="ConsolePanel.js"></script>
+    <script type="text/javascript" src="ExtensionAPI.js"></script>
+    <script type="text/javascript" src="ExtensionServer.js"></script>
+    <script type="text/javascript" src="ExtensionPanel.js"></script>
     <script type="text/javascript" src="AuditsPanel.js"></script>
     <script type="text/javascript" src="AuditResultView.js"></script>
     <script type="text/javascript" src="AuditLauncherView.js"></script>
diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js
index 0adf057..4bb30c7 100644
--- a/WebCore/inspector/front-end/inspector.js
+++ b/WebCore/inspector/front-end/inspector.js
@@ -526,6 +526,9 @@ WebInspector.loaded = function()
     document.getElementById("close-button-left").addEventListener("click", this.close, true);
     document.getElementById("close-button-right").addEventListener("click", this.close, true);
 
+    this.extensionServer = new WebInspector.ExtensionServer();
+    this.extensionServer.initExtensions();
+
     InspectorFrontendHost.loaded();
 }
 
@@ -1202,6 +1205,7 @@ WebInspector.updateResource = function(identifier, payload)
         resource.finished = payload.finished;
         if (this.panels.audits)
             this.panels.audits.resourceFinished(resource);
+        this.extensionServer.notifyResourceFinished(resource);
     }
 
     if (payload.didTimingChange) {
@@ -1426,6 +1430,7 @@ WebInspector.reset = function()
     delete this.mainResource;
 
     this.console.clearMessages();
+    this.extensionServer.notifyInspectorReset();
 }
 
 WebInspector.resetProfilesPanel = function()
@@ -1442,6 +1447,7 @@ WebInspector.bringToFront = function()
 WebInspector.inspectedURLChanged = function(url)
 {
     InspectorFrontendHost.inspectedURLChanged(url);
+    this.extensionServer.notifyInspectedURLChanged();
 }
 
 WebInspector.resourceURLChanged = function(resource, oldURL)
@@ -1454,6 +1460,7 @@ WebInspector.didCommitLoad = function()
 {
     // Cleanup elements panel early on inspected page refresh.
     WebInspector.setDocument(null);
+    this.extensionServer.notifyInspectedPageLoaded();
 }
 
 WebInspector.updateConsoleMessageExpiredCount = function(count)

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list