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

caseq at chromium.org caseq at chromium.org
Wed Dec 22 12:50:09 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 58f64c7b95d47acd634bc03158d8b120f25727a6
Author: caseq at chromium.org <caseq at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Aug 31 12:38:51 2010 +0000

    2010-08-30  Andrey Kosyakov  <caseq at chromium.org>
    
            Reviewed by Yury Semikhatsky.
    
            Web Inspector: add audits support to extension API
            Exposed (late) adding of categories from AuditPanel.
            Removed indexOfObjectInListSortedByFunction in favor of
            insertionIndexForObjectInListSortedByFunction (the former had
            weird interface always returning negative numbers and was only used in
            the latter).
            https://bugs.webkit.org/show_bug.cgi?id=44518
    
            Tests: inspector/extensions-audits-api.html
                   inspector/extensions-audits.html
    
            * WebCore.gypi:
            * WebCore.vcproj/WebCore.vcproj:
            * inspector/front-end/AuditFormatters.js: Added.
            (WebInspector.applyFormatters):
            (WebInspector.AuditFormatters.text):
            (WebInspector.AuditFormatters.snippet):
            (WebInspector.AuditFormatters.concat):
            (WebInspector.AuditFormatters.url):
            * inspector/front-end/AuditLauncherView.js:
            (WebInspector.AuditLauncherView):
            (WebInspector.AuditLauncherView.prototype.addCategory.compareCategories):
            (WebInspector.AuditLauncherView.prototype.addCategory):
            (WebInspector.AuditLauncherView.prototype._launchButtonClicked):
            (WebInspector.AuditLauncherView.prototype._selectAllClicked):
            (WebInspector.AuditLauncherView.prototype._categoryClicked):
            (WebInspector.AuditLauncherView.prototype._createCategoryElement):
            (WebInspector.AuditLauncherView.prototype._createLauncherUI):
            * inspector/front-end/AuditResultView.js:
            (WebInspector.AuditCategoryResultPane.prototype._appendResult):
            * inspector/front-end/AuditsPanel.js:
            (WebInspector.AuditsPanel):
            (WebInspector.AuditsPanel.prototype.addCategory):
            (WebInspector.AuditsPanel.prototype.getCategory):
            (WebInspector.AuditsPanel.prototype._executeAudit):
            (WebInspector.AuditCategory.prototype.run):
            * inspector/front-end/ExtensionAPI.js:
            (WebInspector.injectedExtensionAPI):
            (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype.addListener):
            (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._fire):
            (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._dispatch):
            (WebInspector.injectedExtensionAPI.EventSink):
            (WebInspector.injectedExtensionAPI.InspectorExtensionAPI):
            (WebInspector.injectedExtensionAPI.Panels.prototype.create):
            (WebInspector.injectedExtensionAPI.Audits):
            (WebInspector.injectedExtensionAPI.Audits.prototype.addCategory):
            (WebInspector.injectedExtensionAPI.AuditCategory.customDispatch):
            (WebInspector.injectedExtensionAPI.AuditCategory):
            (WebInspector.injectedExtensionAPI.AuditCategoryImpl):
            (WebInspector.injectedExtensionAPI.AuditResult):
            (WebInspector.injectedExtensionAPI.AuditResult.prototype.get Severity):
            (WebInspector.injectedExtensionAPI.AuditResultImpl):
            (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.addResult):
            (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.createResult):
            (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.done):
            (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype._nodeFactory):
            (WebInspector.injectedExtensionAPI.AuditResultNode):
            (WebInspector.injectedExtensionAPI.AuditResultNode.prototype.addChild):
            * inspector/front-end/ExtensionAuditCategory.js: Added.
            (WebInspector.ExtensionAuditCategory):
            (WebInspector.ExtensionAuditCategory.prototype.get id):
            (WebInspector.ExtensionAuditCategory.prototype.get displayName):
            (WebInspector.ExtensionAuditCategory.prototype.get ruleCount):
            (WebInspector.ExtensionAuditCategory.prototype.run):
            (WebInspector.ExtensionAuditCategoryResults):
            (WebInspector.ExtensionAuditCategoryResults.prototype.get complete):
            (WebInspector.ExtensionAuditCategoryResults.prototype.cancel):
            (WebInspector.ExtensionAuditCategoryResults.prototype.addResult):
            (WebInspector.ExtensionAuditCategoryResults.prototype._addNode):
            (WebInspector.ExtensionAuditCategoryResults.prototype._addResult):
            * inspector/front-end/ExtensionCommon.js: Added.
            (WebInspector.commonExtensionSymbols):
            * inspector/front-end/ExtensionServer.js:
            (WebInspector.ExtensionServer):
            (WebInspector.ExtensionServer.prototype.startAuditRun):
            (WebInspector.ExtensionServer.prototype.stopAuditRun):
            (WebInspector.ExtensionServer.prototype._postNotification):
            (WebInspector.ExtensionServer.prototype._onAddAuditCategory):
            (WebInspector.ExtensionServer.prototype._onAddAuditResult):
            (WebInspector.ExtensionServer.prototype._onStopAuditCategoryRun):
            (WebInspector.ExtensionServer.prototype._addExtensions):
            (WebInspector.ExtensionServer.prototype._buildExtensionAPIInjectedScript):
            (WebInspector.ExtensionStatus):
            * inspector/front-end/WebKit.qrc:
            * inspector/front-end/inspector.html:
            * inspector/front-end/utilities.js:
            ():
    
    2010-08-30  Andrey Kosyakov  <caseq at chromium.org>
    
            Reviewed by Yury Semikhatsky.
    
            Web Inspector: add audits support to extension API
            https://bugs.webkit.org/show_bug.cgi?id=44518
    
            * http/tests/inspector/inspector-test2.js:
            (initialize_InspectorTest):
            (runTest.runTestInFrontend):
            (runTest):
            * inspector/audits-panel-functional.html:
            * inspector/audits-tests.js: Added.
            (frontend_collectAuditResults):
            (frontend_collectTextContent):
            * inspector/audits-tests2.js: Added.
            (initialize_AuditTests.InspectorTest.collectAuditResults):
            (initialize_AuditTests.InspectorTest.collectTextContent):
            (initialize_AuditTests):
            * inspector/extensions-api-expected.txt:
            * inspector/extensions-api.html:
            * inspector/extensions-audits-api-expected.txt: Added.
            * inspector/extensions-audits-api.html: Added.
            * inspector/extensions-audits-expected.txt: Added.
            * inspector/extensions-audits-tests.js: Added.
            (extension_runAudits.onMessage):
            (extension_runAudits):
            (initialize_ExtensionsAuditsTest.InspectorTest.startExtensionAudits.onAuditsDone):
            (initialize_ExtensionsAuditsTest.InspectorTest.startExtensionAudits):
            (initialize_ExtensionsAuditsTest):
            (test):
            * inspector/extensions-audits.html: Added.
            * inspector/extensions-expected.txt:
            * inspector/extensions-test.js:
            (extensionFunctions):
            (initialize_ExtensionsTest.InspectorTest.dispatchOnMessage):
            (initialize_ExtensionsTest.InspectorTest.runExtensionTests):
            (test):
            * inspector/extensions.html:
            * inspector/resources/audits-script3.js: Removed.
            * inspector/resources/extension-main.js:
            (onTestsDone):
            * platform/chromium/test_expectations.txt:
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66477 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index a9c9b31..d6a7ea5 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,47 @@
+2010-08-30  Andrey Kosyakov  <caseq at chromium.org>
+
+        Reviewed by Yury Semikhatsky.
+
+        Web Inspector: add audits support to extension API
+        https://bugs.webkit.org/show_bug.cgi?id=44518
+
+        * http/tests/inspector/inspector-test2.js:
+        (initialize_InspectorTest):
+        (runTest.runTestInFrontend):
+        (runTest):
+        * inspector/audits-panel-functional.html:
+        * inspector/audits-tests.js: Added.
+        (frontend_collectAuditResults):
+        (frontend_collectTextContent):
+        * inspector/audits-tests2.js: Added.
+        (initialize_AuditTests.InspectorTest.collectAuditResults):
+        (initialize_AuditTests.InspectorTest.collectTextContent):
+        (initialize_AuditTests):
+        * inspector/extensions-api-expected.txt:
+        * inspector/extensions-api.html:
+        * inspector/extensions-audits-api-expected.txt: Added.
+        * inspector/extensions-audits-api.html: Added.
+        * inspector/extensions-audits-expected.txt: Added.
+        * inspector/extensions-audits-tests.js: Added.
+        (extension_runAudits.onMessage):
+        (extension_runAudits):
+        (initialize_ExtensionsAuditsTest.InspectorTest.startExtensionAudits.onAuditsDone):
+        (initialize_ExtensionsAuditsTest.InspectorTest.startExtensionAudits):
+        (initialize_ExtensionsAuditsTest):
+        (test):
+        * inspector/extensions-audits.html: Added.
+        * inspector/extensions-expected.txt:
+        * inspector/extensions-test.js:
+        (extensionFunctions):
+        (initialize_ExtensionsTest.InspectorTest.dispatchOnMessage):
+        (initialize_ExtensionsTest.InspectorTest.runExtensionTests):
+        (test):
+        * inspector/extensions.html:
+        * inspector/resources/audits-script3.js: Removed.
+        * inspector/resources/extension-main.js:
+        (onTestsDone):
+        * platform/chromium/test_expectations.txt:
+
 2010-08-24  Jeremy Orlow  <jorlow at chromium.org>
 
         Reviewed by Steve Block.
diff --git a/LayoutTests/http/tests/inspector/inspector-test2.js b/LayoutTests/http/tests/inspector/inspector-test2.js
index 4d8bf7b..4fb562b 100644
--- a/LayoutTests/http/tests/inspector/inspector-test2.js
+++ b/LayoutTests/http/tests/inspector/inspector-test2.js
@@ -32,6 +32,21 @@ InspectorTest.reloadPage = function(callback)
     InspectorTest._addSniffer(WebInspector, "reset", callback);
 };
 
+InspectorTest.enableResourceTracking = function(callback)
+{
+    if (WebInspector.panels.resources.resourceTrackingEnabled)
+        callback();
+    else {
+        InspectorTest._addSniffer(WebInspector, "reset", callback);
+        InspectorBackend.enableResourceTracking(false);
+    }
+}
+
+InspectorTest.disableResourceTracking = function()
+{
+    InspectorBackend.disableResourceTracking(false);
+}
+
 InspectorTest.findDOMNode = function(root, filter, callback)
 {
     var found = false;
@@ -118,8 +133,13 @@ function runTest()
         InspectorTest = {};
         InspectorTest.completeTestCallId = completeTestCallId;
 
-        for (var i = 0; i < initializationFunctions.length; ++i)
-            initializationFunctions[i]();
+        for (var i = 0; i < initializationFunctions.length; ++i) {
+            try {
+                initializationFunctions[i]();
+            } catch (e) {
+                console.error("Exception in test initialization: " + e);
+            }
+        }
 
         WebInspector.showPanel("elements");
         testFunction();
diff --git a/LayoutTests/inspector/audits-panel-functional.html b/LayoutTests/inspector/audits-panel-functional.html
index 71537f4..e7a2804 100644
--- a/LayoutTests/inspector/audits-panel-functional.html
+++ b/LayoutTests/inspector/audits-panel-functional.html
@@ -7,12 +7,12 @@
 }
 </style>
 <script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="audits-tests.js"></script>
 
 <!-- These scripts are needed to result in a violation of the max JS resource count from the same domain -->
 <script src="resources/audits-script1.js"></script>
 <link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
 <script src="resources/audits-script2.js"></script>
-<script src="resources/audits-script3.js"></script>
 <script>
 
 function doit()
@@ -50,14 +50,7 @@ function frontend_runAudits(testController)
 
         testController.runAfterPendingDispatches(function() {
             // Audits are done, check results.
-            WebInspector.panels.audits.showResults(WebInspector.panels.audits.auditResultsTreeElement.children[0].results);
-            var liElements = WebInspector.panels.audits.visibleView.element.getElementsByTagName("li");
-            for (var j = 0; j < liElements.length; ++j) {
-                if (liElements[j].treeElement)
-                    liElements[j].treeElement.expand();
-            }
-            var output = [];
-            frontend_collectTextContent(WebInspector.panels.audits.visibleView.element, 0, output);
+            var output = frontend_collectAuditResults();
             // Avoid influencing tests that require resource tracking to be disabled.
             InspectorBackend.disableResourceTracking(false);
             testController.runAfterPendingDispatches(function() {
@@ -69,29 +62,6 @@ function frontend_runAudits(testController)
     }
 }
 
-function frontend_collectTextContent(element, level, output)
-{
-    var nodeOutput = "";
-    var child = element.firstChild;
-    while (child) {
-        if (child.nodeType === Node.TEXT_NODE) {
-            for (var i = 0; i < level; ++i)
-                nodeOutput += " ";
-            nodeOutput += child.nodeValue;
-        } else if (child.nodeType === Node.ELEMENT_NODE) {
-            if (nodeOutput !== "") {
-                output.push(nodeOutput);
-                nodeOutput = "";
-            }
-            frontend_collectTextContent(child, level + 1, output);
-        }
-        child = child.nextSibling;
-    }
-    if (nodeOutput !== "")
-        output.push(nodeOutput);
-    return;
-}
-
 </script>
 </head>
 
diff --git a/LayoutTests/inspector/audits-tests.js b/LayoutTests/inspector/audits-tests.js
new file mode 100755
index 0000000..102c6b4
--- /dev/null
+++ b/LayoutTests/inspector/audits-tests.js
@@ -0,0 +1,35 @@
+function frontend_collectAuditResults()
+{
+    WebInspector.panels.audits.showResults(WebInspector.panels.audits.auditResultsTreeElement.children[0].results);
+    var liElements = WebInspector.panels.audits.visibleView.element.getElementsByTagName("li");
+    for (var j = 0; j < liElements.length; ++j) {
+        if (liElements[j].treeElement)
+            liElements[j].treeElement.expand();
+    }
+    var output = [];
+    frontend_collectTextContent(WebInspector.panels.audits.visibleView.element, 0, output);
+    return output;
+}
+
+function frontend_collectTextContent(element, level, output)
+{
+    var nodeOutput = "";
+    var child = element.firstChild;
+
+    while (child) {
+        if (child.nodeType === Node.TEXT_NODE) {
+            for (var i = 0; i < level; ++i)
+                nodeOutput += " ";
+            nodeOutput += child.nodeValue;
+        } else if (child.nodeType === Node.ELEMENT_NODE) {
+            if (nodeOutput !== "") {
+                output.push(nodeOutput);
+                nodeOutput = "";
+            }
+            frontend_collectTextContent(child, level + 1, output);
+        }
+        child = child.nextSibling;
+    }
+    if (nodeOutput !== "")
+        output.push(nodeOutput);
+}
diff --git a/LayoutTests/inspector/audits-tests2.js b/LayoutTests/inspector/audits-tests2.js
new file mode 100755
index 0000000..554f3c3
--- /dev/null
+++ b/LayoutTests/inspector/audits-tests2.js
@@ -0,0 +1,38 @@
+function initialize_AuditTests()
+{
+
+InspectorTest.collectAuditResults = function()
+{
+    WebInspector.panels.audits.showResults(WebInspector.panels.audits.auditResultsTreeElement.children[0].results);
+    var liElements = WebInspector.panels.audits.visibleView.element.getElementsByTagName("li");
+    for (var j = 0; j < liElements.length; ++j) {
+        if (liElements[j].treeElement)
+            liElements[j].treeElement.expand();
+    }
+    InspectorTest.collectTextContent(WebInspector.panels.audits.visibleView.element, 0);
+}
+
+InspectorTest.collectTextContent = function(element, level)
+{
+    var nodeOutput = "";
+    var child = element.firstChild;
+
+    while (child) {
+        if (child.nodeType === Node.TEXT_NODE) {
+            for (var i = 0; i < level; ++i)
+                nodeOutput += " ";
+            nodeOutput += child.nodeValue;
+        } else if (child.nodeType === Node.ELEMENT_NODE) {
+            if (nodeOutput !== "") {
+                InspectorTest.addResult(nodeOutput);
+                nodeOutput = "";
+            }
+            InspectorTest.collectTextContent(child, level + 1);
+        }
+        child = child.nextSibling;
+    }
+    if (nodeOutput !== "")
+        InspectorTest.addResult(nodeOutput);
+}
+
+}
diff --git a/LayoutTests/inspector/extensions-api-expected.txt b/LayoutTests/inspector/extensions-api-expected.txt
index 35a99d2..c07471b 100644
--- a/LayoutTests/inspector/extensions-api-expected.txt
+++ b/LayoutTests/inspector/extensions-api-expected.txt
@@ -4,6 +4,9 @@ Started extension.
 Running tests...
 RUNNING TEST: extension_testAPI
 {
+    audits : {
+        addCategory : <function>
+    }
     inspectedWindow : {
         onLoaded : {
             addListener : <function>
diff --git a/LayoutTests/inspector/extensions-api.html b/LayoutTests/inspector/extensions-api.html
index 560cff7..fc9da0f 100644
--- a/LayoutTests/inspector/extensions-api.html
+++ b/LayoutTests/inspector/extensions-api.html
@@ -1,6 +1,6 @@
 <html>
 <head>
-<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="../http/tests/inspector/inspector-test2.js"></script>
 <script src="extensions-test.js"></script>
 <script type="text/javascript">
 
@@ -12,7 +12,7 @@ function extension_testAPI(nextTest)
 
 </script>
 </head>
-<body onload="onload()">
+<body onload="runTest()">
 <p>Tests public interface of WebInspector Extensions API</p>
 </body>
 </html>
diff --git a/LayoutTests/inspector/extensions-audits-api-expected.txt b/LayoutTests/inspector/extensions-audits-api-expected.txt
new file mode 100644
index 0000000..1072aa5
--- /dev/null
+++ b/LayoutTests/inspector/extensions-audits-api-expected.txt
@@ -0,0 +1,38 @@
+Tests audits support in WebInspector Extensions API
+
+Started extension.
+Running tests...
+RUNNING TEST: extension_testAuditsAPI
+Added audit category, result dump follows:
+{
+    onAuditStarted : {
+        addListener : <function>
+        removeListener : <function>
+    }
+}
+category.onAuditStarted fired, results dump follows:
+{
+    addResult : <function>
+    createResult : <function>
+    done : <function>
+    url : <function>
+    snippet : <function>
+    text : <function>
+    Severity : {
+        Info : "info"
+        Warning : "warning"
+        Severe : "severe"
+    }
+}
+{
+    contents : {
+        0 : "Subtree"
+    }
+    children : {
+    }
+    expanded : false
+    addChild : <function>
+}
+All tests done.
+  Extension audits
+
diff --git a/LayoutTests/inspector/extensions-audits-api.html b/LayoutTests/inspector/extensions-audits-api.html
new file mode 100755
index 0000000..118fe0d
--- /dev/null
+++ b/LayoutTests/inspector/extensions-audits-api.html
@@ -0,0 +1,32 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test2.js"></script>
+<script src="extensions-test.js"></script>
+<script src="audits-tests2.js"></script>
+<script src="extensions-audits-tests.js"></script>
+
+<script type="text/javascript">
+
+function extension_testAuditsAPI(nextTest)
+{
+    function onStartAuditCategory(results)
+    {
+        output("category.onAuditStarted fired, results dump follows:");
+        dumpObject(results);
+        var node = results.createResult("Subtree");
+        dumpObject(node);
+        results.done();
+    }
+    var category = webInspector.audits.addCategory("Extension audits", 20);
+    category.onAuditStarted.addListener(onStartAuditCategory);
+    output("Added audit category, result dump follows:");
+    dumpObject(category);
+    extension_runAudits(nextTest);
+}
+
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests audits support in WebInspector Extensions API</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/extensions-audits-expected.txt b/LayoutTests/inspector/extensions-audits-expected.txt
new file mode 100644
index 0000000..a1eee73
--- /dev/null
+++ b/LayoutTests/inspector/extensions-audits-expected.txt
@@ -0,0 +1,28 @@
+Tests audits support in WebInspector Extensions API
+
+Started extension.
+Running tests...
+RUNNING TEST: extension_testAudits
+Added audit category.
+category.onAuditStarted fired
+failedCategory.onAuditStarted fired, throwing exception
+All tests done.
+  Extension audits
+    Failed rule (42)
+     this rule always fails
+    Rule with details subtree (1)
+     This rule has a lot of details
+      Subtree
+       Some url: 
+        WebKit
+        more text 
+        http://www.google.com
+       ... and a snippet
+         function rand()
+         {
+             return 4;
+         }
+    Passed rule
+     this rule always passes ok
+  Extension audits that fail
+
diff --git a/LayoutTests/inspector/extensions-audits-tests.js b/LayoutTests/inspector/extensions-audits-tests.js
new file mode 100644
index 0000000..3bb1fc2
--- /dev/null
+++ b/LayoutTests/inspector/extensions-audits-tests.js
@@ -0,0 +1,44 @@
+function extension_runAudits(callback)
+{
+    function onMessage(event)
+    {
+        if (event.data === "audits-complete")
+            callback();
+    }
+    window.addEventListener("message", onMessage, false);
+    top.postMessage("run-audits", "*");
+}
+
+// runs in front-end
+var initialize_ExtensionsAuditsTest = function()
+{
+    InspectorTest.startExtensionAudits = function() 
+    {
+        const launcherView = WebInspector.panels.audits._launcherView;
+        launcherView._selectAllClicked(false);
+        launcherView._auditPresentStateElement.checked = true;
+
+        var extensionCategories = document.evaluate("label[starts-with(.,'Extension ')]/input[@type='checkbox']",
+            WebInspector.panels.audits._launcherView._categoriesElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+        for (var i = 0; i < extensionCategories.snapshotLength; ++i)
+            extensionCategories.snapshotItem(i).click();
+
+        function onAuditsDone()
+        {
+            InspectorTest.collectAuditResults();
+            for (var i = 0; i < frames.length; ++i)
+                frames[i].postMessage("audits-complete", "*");
+        }
+
+        InspectorTest._addSniffer(WebInspector.panels.audits, "_auditFinishedCallback", onAuditsDone, true);
+        launcherView._launchButtonClicked();
+    }
+}
+
+var test = function()
+{
+    InspectorTest.dispatchOnMessage("run-audits", InspectorTest.startExtensionAudits);
+    InspectorTest.runExtensionTests();
+}
+
diff --git a/LayoutTests/inspector/extensions-audits.html b/LayoutTests/inspector/extensions-audits.html
new file mode 100755
index 0000000..ef65d51
--- /dev/null
+++ b/LayoutTests/inspector/extensions-audits.html
@@ -0,0 +1,59 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test2.js"></script>
+<script src="extensions-test.js"></script>
+<script src="audits-tests2.js"></script>
+<script src="extensions-audits-tests.js"></script>
+
+<script type="text/javascript">
+
+function extension_testAudits(nextTest)
+{
+    function onStartAuditCategory(results)
+    {
+        output("category.onAuditStarted fired");
+        results.addResult("Passed rule", "this rule always passes ok", results.Severity.Info);
+        results.addResult("Failed rule (42)", "this rule always fails", results.Severity.Severe);
+
+        var node = results.createResult("Subtree");
+        node.addChild("Some url: ", results.url("http://www.webkit.org", "WebKit"), " more text ", results.url("http://www.google.com"));
+        var nestedNode = node.addChild("... and a snippet");
+        nestedNode.expanded = true;
+        nestedNode.addChild(results.snippet("function rand()\n{\n    return 4;\n}"));
+
+        results.addResult("Rule with details subtree (1)", "This rule has a lot of details", results.Severity.Warning, node);
+        // Audit normally terminates when number of added rule results is equal to
+        // the rule count declared when adding a category. done() is only for
+        // emergency cases, when we know we won't be able to run the rest of the rules.
+        results.done();
+    }
+    function onStartAuditFailedCategory()
+    {
+        output("failedCategory.onAuditStarted fired, throwing exception");
+        throw "oops!";
+    }
+    function onStartAuditDisabledCategory(results)
+    {
+        output("FAIL: failedCategory.onAuditStarted fired");
+        results.done();
+    }
+
+    var category = webInspector.audits.addCategory("Extension audits", 20);
+    category.onAuditStarted.addListener(onStartAuditCategory);
+    output("Added audit category.");
+
+    var failedCategory = webInspector.audits.addCategory("Extension audits that fail", 2);
+    failedCategory.onAuditStarted.addListener(onStartAuditFailedCategory);
+
+    var disabledCategory = webInspector.audits.addCategory("Disabled extension audits", 2);
+    disabledCategory.onAuditStarted.addListener(onStartAuditDisabledCategory);
+
+    extension_runAudits(nextTest);
+}
+
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests audits support in WebInspector Extensions API</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/extensions-expected.txt b/LayoutTests/inspector/extensions-expected.txt
index 3924a6a..8319434 100644
--- a/LayoutTests/inspector/extensions-expected.txt
+++ b/LayoutTests/inspector/extensions-expected.txt
@@ -27,11 +27,11 @@ Evaluate: TypeError: JSON.stringify cannot serialize cyclic structures.(exceptio
 RUNNING TEST: extension_testEvalOk
 Evaluate: {"str":"foo","num":42}(exception: undefined)
 RUNNING TEST: extension_testGetAllResources
-resource: .../tests/inspector/inspector-test.js
+resource: .../tests/inspector/inspector-test2.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}
+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
index 00d8ef5..cd9f293 100644
--- a/LayoutTests/inspector/extensions-test.js
+++ b/LayoutTests/inspector/extensions-test.js
@@ -3,36 +3,53 @@ function log(message)
     output(message);
 }
 
-function frontend_initializeExtension(url)
+function extensionFunctions()
 {
-    if (WebInspector.panels.resources.resourceTrackingEnabled)
-        WebInspector.addExtensions([{ startPage: url }]);
-    else
-        InspectorBackend.enableResourceTracking(false);
+    var functions = "";
+
+    for (symbol in window) {
+        if (/^extension_/.exec(symbol) && typeof window[symbol] === "function")
+            functions += window[symbol].toString();
+    }
+    return functions;
 }
 
-function doit()
+var initialize_ExtensionsTest = function()
 {
-    var extensionURL = location.href.replace(/\/[^/]*$/, "/resources/extension-main.html");
-    evaluateInWebInspector("frontend_initializeExtension('" + extensionURL + "')");
-}
 
-function done()
+InspectorTest.dispatchOnMessage = function(messageId, callback)
 {
-    function callback()
+    function onMessage(event)
     {
-        notifyDone();
+        if (event.data === messageId) {
+            window.removeEventListener("message", onMessage, false);
+            callback();
+        }
     }
-    evaluateInWebInspector("InspectorBackend.disableResourceTracking(false);", callback);
+    window.addEventListener("message", onMessage, false);
 }
 
-function extensionFunctions()
+InspectorTest.runExtensionTests = function()
 {
-    var functions = "";
+    function addExtension(callback)
+    {
+        InjectedScriptAccess.getDefault().evaluate("location.href", "console", function(result) {
+            var extensionURL = result.description.replace(/\/[^/]*$/, "/resources/extension-main.html");
+            WebInspector.addExtensions([{ startPage: extensionURL }]);
+            if (callback)
+                callback();
+        });
+    } 
+    InspectorTest.dispatchOnMessage("extension-tests-done", function() {
+        InspectorTest.disableResourceTracking();
+        InspectorTest.completeTest();
+    });
+    InspectorTest.enableResourceTracking(addExtension);
+}
 
-    for (symbol in window) {
-        if (/^extension_/.exec(symbol) && typeof window[symbol] === "function")
-            functions += window[symbol].toString();
-    }
-    return functions;
+}
+
+var test = function()
+{
+    InspectorTest.runExtensionTests();
 }
diff --git a/LayoutTests/inspector/extensions.html b/LayoutTests/inspector/extensions.html
index 63c682b..9259b94 100644
--- a/LayoutTests/inspector/extensions.html
+++ b/LayoutTests/inspector/extensions.html
@@ -1,6 +1,6 @@
 <html>
 <head>
-<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="../http/tests/inspector/inspector-test2.js"></script>
 <script src="extensions-test.js"></script>
 <script type="text/javascript">
 
@@ -28,7 +28,7 @@ function extension_testGetAllResources(nextTest)
         var resources = result.sort(compareResources);
 
         for (var i = 0; i < resources.length; ++i)
-            log("resource: " + resources[i].har.request.url.replace(/.*((\/[^/]*){3}$)/,"...$1"));
+            output("resource: " + resources[i].har.request.url.replace(/.*((\/[^/]*){3}$)/,"...$1"));
     }
     webInspector.resources.getAll(callbackAndNextTest(onResource, nextTest));
 }
@@ -37,7 +37,7 @@ function extension_testGetInvalidResource(nextTest)
 {
     function onResource(result)
     {
-        log("Attempted to retrieve invalid resource: " + JSON.stringify(result));
+        output("Attempted to retrieve invalid resource: " + JSON.stringify(result));
     }
     webInspector.resources.get(2128506, callbackAndNextTest(onResource, nextTest));
 }
@@ -46,18 +46,18 @@ function extension_testCreatePanel(nextTest)
 {
     function onPanelCreated(panel)
     {
-        log("Panel created");
+        output("Panel created");
         dumpObject(panel);
     }
     webInspector.panels.create("Test Panel", "extension-panel.html", "extension-panel.png", callbackAndNextTest(onPanelCreated, nextTest));
-    log("done createPanel");
+    output("done createPanel");
 }
 
 function extension_testCreateSidebar(nextTest)
 {
     function onSidebarCreated(sidebar)
     {
-        log("Sidebar created");
+        output("Sidebar created");
         dumpObject(sidebar);
     }
     webInspector.panels.scripts.createSidebarPane("Test Sidebar", "extension-sidebar.html", callbackAndNextTest(onSidebarCreated, nextTest));
@@ -67,7 +67,7 @@ function extension_testResourceNotification(nextTest)
 {
     function onResourceFinished(resource)
     {
-        log("Resource finished: " + resource.har.request.url.replace(/.*((\/[^/]*){3}$)/,"...$1"));
+        output("Resource finished: " + resource.har.request.url.replace(/.*((\/[^/]*){3}$)/,"...$1"));
     }
 
     webInspector.resources.onFinished.addListener(callbackAndNextTest(onResourceFinished, nextTest));
@@ -76,12 +76,12 @@ function extension_testResourceNotification(nextTest)
 
 function extension_onEvaluate(result)
 {
-    log("Evaluate: " + result.value + "(exception: " + result.isException + ")");
+    output("Evaluate: " + result.value + "(exception: " + result.isException + ")");
 }
 
 </script>
 </head>
-<body onload="onload()">
+<body onload="runTest()">
 <p>Tests WebInspector extension API</p>
 </body>
 </html>
diff --git a/LayoutTests/inspector/resources/audits-script3.js b/LayoutTests/inspector/resources/audits-script3.js
deleted file mode 100755
index fd60504..0000000
--- a/LayoutTests/inspector/resources/audits-script3.js
+++ /dev/null
@@ -1,3 +0,0 @@
-function foo3()
-{
-}
diff --git a/LayoutTests/inspector/resources/extension-main.html b/LayoutTests/inspector/resources/extension-main.html
index e068e8f..160b088 100644
--- a/LayoutTests/inspector/resources/extension-main.html
+++ b/LayoutTests/inspector/resources/extension-main.html
@@ -1,15 +1,15 @@
 <html>
 <head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
 <script type="text/javascript">
-function log(message)
+function output(message)
 {
-    webInspector.inspectedWindow.evaluate("log(unescape('" + escape(message) + "'));");
+    webInspector.inspectedWindow.evaluate("output(unescape('" + escape(message) + "'));");
 }
 
-log("Started extension.");
+output("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
index 9bc6bb3..b1a47bd 100644
--- a/LayoutTests/inspector/resources/extension-main.js
+++ b/LayoutTests/inspector/resources/extension-main.js
@@ -11,10 +11,10 @@ function fetchTests()
 
 function runTests()
 {
-    log("Running tests...");
+    output("Running tests...");
     var tests = [];
     for (var symbol in this) {
-        if (/^extension_test/.exec(symbol) && typeof this[symbol] === "function")
+        if (/^extension_test/.test(symbol) && typeof this[symbol] === "function")
             tests.push(symbol);
     }
     tests = tests.sort();
@@ -26,17 +26,17 @@ function runTests()
 
 function onTestsDone()
 {
-    log("All tests done.");
-    webInspector.inspectedWindow.evaluate("done();");
+    output("All tests done.");
+    top.postMessage("extension-tests-done","*");
 }
 
 function runTest(test, name)
 {
-    log("RUNNING TEST: " + name);
+    output("RUNNING TEST: " + name);
     try {
         test();
     } catch (e) {
-        log(name + ": " + e);
+        output(name + ": " + e);
     }
 }
 
@@ -56,11 +56,4 @@ function bind(func, thisObject)
     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/platform/chromium/test_expectations.txt b/LayoutTests/platform/chromium/test_expectations.txt
index ee8fa0d..53238dd 100644
--- a/LayoutTests/platform/chromium/test_expectations.txt
+++ b/LayoutTests/platform/chromium/test_expectations.txt
@@ -200,6 +200,8 @@ 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
 WONTFIX SKIP : inspector/extensions-api.html = FAIL
+WONTFIX SKIP : inspector/extensions-audits.html = FAIL
+WONTFIX SKIP : inspector/extensions-audits-api.html = FAIL
 
 // Implement java testing harness.
 BUG36681 DEFER SKIP : java = TEXT
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index a120d5a..11ab99f 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,95 @@
+2010-08-30  Andrey Kosyakov  <caseq at chromium.org>
+
+        Reviewed by Yury Semikhatsky.
+
+        Web Inspector: add audits support to extension API
+        Exposed (late) adding of categories from AuditPanel.
+        Removed indexOfObjectInListSortedByFunction in favor of
+        insertionIndexForObjectInListSortedByFunction (the former had
+        weird interface always returning negative numbers and was only used in
+        the latter).
+        https://bugs.webkit.org/show_bug.cgi?id=44518
+
+        Tests: inspector/extensions-audits-api.html
+               inspector/extensions-audits.html
+
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * inspector/front-end/AuditFormatters.js: Added.
+        (WebInspector.applyFormatters):
+        (WebInspector.AuditFormatters.text):
+        (WebInspector.AuditFormatters.snippet):
+        (WebInspector.AuditFormatters.concat):
+        (WebInspector.AuditFormatters.url):
+        * inspector/front-end/AuditLauncherView.js:
+        (WebInspector.AuditLauncherView):
+        (WebInspector.AuditLauncherView.prototype.addCategory.compareCategories):
+        (WebInspector.AuditLauncherView.prototype.addCategory):
+        (WebInspector.AuditLauncherView.prototype._launchButtonClicked):
+        (WebInspector.AuditLauncherView.prototype._selectAllClicked):
+        (WebInspector.AuditLauncherView.prototype._categoryClicked):
+        (WebInspector.AuditLauncherView.prototype._createCategoryElement):
+        (WebInspector.AuditLauncherView.prototype._createLauncherUI):
+        * inspector/front-end/AuditResultView.js:
+        (WebInspector.AuditCategoryResultPane.prototype._appendResult):
+        * inspector/front-end/AuditsPanel.js:
+        (WebInspector.AuditsPanel):
+        (WebInspector.AuditsPanel.prototype.addCategory):
+        (WebInspector.AuditsPanel.prototype.getCategory):
+        (WebInspector.AuditsPanel.prototype._executeAudit):
+        (WebInspector.AuditCategory.prototype.run):
+        * inspector/front-end/ExtensionAPI.js:
+        (WebInspector.injectedExtensionAPI):
+        (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype.addListener):
+        (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._fire):
+        (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._dispatch):
+        (WebInspector.injectedExtensionAPI.EventSink):
+        (WebInspector.injectedExtensionAPI.InspectorExtensionAPI):
+        (WebInspector.injectedExtensionAPI.Panels.prototype.create):
+        (WebInspector.injectedExtensionAPI.Audits):
+        (WebInspector.injectedExtensionAPI.Audits.prototype.addCategory):
+        (WebInspector.injectedExtensionAPI.AuditCategory.customDispatch):
+        (WebInspector.injectedExtensionAPI.AuditCategory):
+        (WebInspector.injectedExtensionAPI.AuditCategoryImpl):
+        (WebInspector.injectedExtensionAPI.AuditResult):
+        (WebInspector.injectedExtensionAPI.AuditResult.prototype.get Severity):
+        (WebInspector.injectedExtensionAPI.AuditResultImpl):
+        (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.addResult):
+        (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.createResult):
+        (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.done):
+        (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype._nodeFactory):
+        (WebInspector.injectedExtensionAPI.AuditResultNode):
+        (WebInspector.injectedExtensionAPI.AuditResultNode.prototype.addChild):
+        * inspector/front-end/ExtensionAuditCategory.js: Added.
+        (WebInspector.ExtensionAuditCategory):
+        (WebInspector.ExtensionAuditCategory.prototype.get id):
+        (WebInspector.ExtensionAuditCategory.prototype.get displayName):
+        (WebInspector.ExtensionAuditCategory.prototype.get ruleCount):
+        (WebInspector.ExtensionAuditCategory.prototype.run):
+        (WebInspector.ExtensionAuditCategoryResults):
+        (WebInspector.ExtensionAuditCategoryResults.prototype.get complete):
+        (WebInspector.ExtensionAuditCategoryResults.prototype.cancel):
+        (WebInspector.ExtensionAuditCategoryResults.prototype.addResult):
+        (WebInspector.ExtensionAuditCategoryResults.prototype._addNode):
+        (WebInspector.ExtensionAuditCategoryResults.prototype._addResult):
+        * inspector/front-end/ExtensionCommon.js: Added.
+        (WebInspector.commonExtensionSymbols):
+        * inspector/front-end/ExtensionServer.js:
+        (WebInspector.ExtensionServer):
+        (WebInspector.ExtensionServer.prototype.startAuditRun):
+        (WebInspector.ExtensionServer.prototype.stopAuditRun):
+        (WebInspector.ExtensionServer.prototype._postNotification):
+        (WebInspector.ExtensionServer.prototype._onAddAuditCategory):
+        (WebInspector.ExtensionServer.prototype._onAddAuditResult):
+        (WebInspector.ExtensionServer.prototype._onStopAuditCategoryRun):
+        (WebInspector.ExtensionServer.prototype._addExtensions):
+        (WebInspector.ExtensionServer.prototype._buildExtensionAPIInjectedScript):
+        (WebInspector.ExtensionStatus):
+        * inspector/front-end/WebKit.qrc:
+        * inspector/front-end/inspector.html:
+        * inspector/front-end/utilities.js:
+        ():
+
 2010-08-31  Justin Schuh  <jschuh at chromium.org>
 
         Reviewed by Nate Chapin.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index ea7e032..89b6d0c 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -4167,6 +4167,7 @@
             'inspector/front-end/AbstractTimelinePanel.js',
             'inspector/front-end/ApplicationCacheItemsView.js',
             'inspector/front-end/AuditCategories.js',
+            'inspector/front-end/AuditFormatters.js',
             'inspector/front-end/AuditLauncherView.js',
             'inspector/front-end/AuditResultView.js',
             'inspector/front-end/AuditRules.js',
@@ -4198,6 +4199,8 @@
             'inspector/front-end/ElementsTreeOutline.js',
             'inspector/front-end/EventListenersSidebarPane.js',
             'inspector/front-end/ExtensionAPI.js',
+            'inspector/front-end/ExtensionAuditCategory.js',
+            'inspector/front-end/ExtensionCommon.js',
             'inspector/front-end/ExtensionPanel.js',
             'inspector/front-end/ExtensionRegistryStub.js',
             'inspector/front-end/ExtensionServer.js',
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 57e81d3..1ca772d 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -52064,6 +52064,10 @@
 					>
 				</File>
 				<File
+					RelativePath="..\inspector\front-end\AuditFormatters.js"
+					>
+				</File>
+				<File
 					RelativePath="..\inspector\front-end\AuditLauncherView.js"
 					>
 				</File>
@@ -52184,6 +52188,14 @@
 					>
 				</File>
 				<File
+					RelativePath="..\inspector\front-end\ExtensionAuditCategory.js"
+					>
+				</File>
+				<File
+					RelativePath="..\inspector\front-end\ExtensionCommon.js"
+					>
+				</File>
+				<File
 					RelativePath="..\inspector\front-end\ExtensionPanel.js"
 					>
 				</File>
diff --git a/WebCore/inspector/front-end/AuditFormatters.js b/WebCore/inspector/front-end/AuditFormatters.js
new file mode 100755
index 0000000..de277ad
--- /dev/null
+++ b/WebCore/inspector/front-end/AuditFormatters.js
@@ -0,0 +1,86 @@
+/*
+ * 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.applyFormatters = function(value)
+{
+    var formatter;
+    var type = typeof value;
+    var args;
+
+    switch (type) {
+        case "string":
+        case "boolean":
+        case "number":
+            formatter = WebInspector.AuditFormatters.text;
+            args = [ value.toString() ];
+            break;
+
+        case "object":
+            if (value instanceof Array) {
+                formatter = WebInspector.AuditFormatters.concat;
+                args = value;
+            } else if (value.type && value.arguments) {
+                formatter = WebInspector.AuditFormatters[value.type];
+                args = value.arguments;
+            }
+    }
+    if (!formatter)
+        throw "Invalid value or formatter: " + type + JSON.stringify(value);
+
+    return formatter.apply(null, args);
+}
+
+WebInspector.AuditFormatters = {
+    text: function(text)
+    {
+        return document.createTextNode(text);
+    },
+
+    snippet: function(snippetText)
+    {
+        var div = document.createElement("div");
+        div.innerText = snippetText;
+        div.className = "source-code";
+        return div;
+    },
+
+    concat: function()
+    {
+        var parent = document.createElement("span");
+        for (var arg = 0; arg < arguments.length; ++arg)
+            parent.appendChild(WebInspector.applyFormatters(arguments[arg]));
+        return parent;
+    },
+
+    url: function(url, displayText)
+    {
+        return WebInspector.linkifyURLAsNode(url, displayText || url, null, (url in WebInspector.resourceURLMap));
+    }
+};
diff --git a/WebCore/inspector/front-end/AuditLauncherView.js b/WebCore/inspector/front-end/AuditLauncherView.js
index 33d3872..18daee6 100644
--- a/WebCore/inspector/front-end/AuditLauncherView.js
+++ b/WebCore/inspector/front-end/AuditLauncherView.js
@@ -28,10 +28,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.AuditLauncherView = function(categoriesById, runnerCallback)
+WebInspector.AuditLauncherView = function(runnerCallback)
 {
     WebInspector.View.call(this);
-    this._categoriesById = categoriesById;
     this._runnerCallback = runnerCallback;
     this._categoryIdPrefix = "audit-category-item-";
     this._auditRunning = false;
@@ -41,27 +40,16 @@ WebInspector.AuditLauncherView = function(categoriesById, runnerCallback)
     this._contentElement = document.createElement("div");
     this._contentElement.className = "audit-launcher-view-content";
     this.element.appendChild(this._contentElement);
+    this._boundCategoryClickListener = this._categoryClicked.bind(this);
 
     this._resetResourceCount();
 
-    function categorySortFunction(a, b)
-    {
-        var aTitle = a.displayName || "";
-        var bTitle = b.displayName || "";
-        return aTitle.localeCompare(bTitle);
-    }
-    var sortedCategories = [];
-    for (var id in this._categoriesById)
-        sortedCategories.push(this._categoriesById[id]);
-    sortedCategories.sort(categorySortFunction);
+    this._sortedCategories = [];
 
-    if (!sortedCategories.length) {
-        this._headerElement = document.createElement("h1");
-        this._headerElement.className = "no-audits";
-        this._headerElement.textContent = WebInspector.UIString("No audits to run");
-        this._contentElement.appendChild(this._headerElement);
-    } else
-        this._createLauncherUI(sortedCategories);
+    this._headerElement = document.createElement("h1");
+    this._headerElement.className = "no-audits";
+    this._headerElement.textContent = WebInspector.UIString("No audits to run");
+    this._contentElement.appendChild(this._headerElement);
 }
 
 WebInspector.AuditLauncherView.prototype = {
@@ -133,6 +121,30 @@ WebInspector.AuditLauncherView.prototype = {
         this._resetResourceCount();
     },
 
+    addCategory: function(category)
+    {
+        if (!this._sortedCategories.length)
+            this._createLauncherUI();
+
+        var categoryElement = this._createCategoryElement(category.displayName, category.id);
+        category._checkboxElement = categoryElement.firstChild;
+        if (this._selectAllCheckboxElement.checked) {
+            category._checkboxElement.checked = true;
+            ++this._currentCategoriesCount;
+        }
+
+        function compareCategories(a, b)
+        {
+            var aTitle = a.displayName || "";
+            var bTitle = b.displayName || "";
+            return aTitle.localeCompare(bTitle);
+        }
+        var insertBefore = insertionIndexForObjectInListSortedByFunction(category, this._sortedCategories, compareCategories);
+        this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]);
+        this._sortedCategories.splice(insertBefore, 0, category);
+        this._updateButton();
+    },
+
     _setAuditRunning: function(auditRunning)
     {
         if (this._auditRunning === auditRunning)
@@ -146,10 +158,11 @@ WebInspector.AuditLauncherView.prototype = {
     {
         var catIds = [];
         var childNodes = this._categoriesElement.childNodes;
-        for (var id in this._categoriesById) {
-            if (this._categoriesById[id]._checkboxElement.checked)
-                catIds.push(id);
+        for (var category = 0; category < this._sortedCategories.length; ++category) {
+            if (this._sortedCategories[category]._checkboxElement.checked)
+                catIds.push(this._sortedCategories[category].id);
         }
+
         this._setAuditRunning(true);
         this._runnerCallback(catIds, this._auditPresentStateElement.checked, this._setAuditRunning.bind(this, false));
     },
@@ -159,14 +172,14 @@ WebInspector.AuditLauncherView.prototype = {
         var childNodes = this._categoriesElement.childNodes;
         for (var i = 0, length = childNodes.length; i < length; ++i)
             childNodes[i].firstChild.checked = checkCategories;
-        this._currentCategoriesCount = checkCategories ? this._totalCategoriesCount : 0;
+        this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0;
         this._updateButton();
     },
 
     _categoryClicked: function(event)
     {
         this._currentCategoriesCount += event.target.checked ? 1 : -1;
-        this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._totalCategoriesCount;
+        this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length;
         this._updateButton();
     },
 
@@ -177,16 +190,21 @@ WebInspector.AuditLauncherView.prototype = {
 
         var element = document.createElement("input");
         element.type = "checkbox";
+        element.addEventListener("click", this._boundCategoryClickListener, false);
         labelElement.appendChild(element);
         labelElement.appendChild(document.createTextNode(title));
 
         return labelElement;
     },
 
-    _createLauncherUI: function(sortedCategories)
+    _createLauncherUI: function()
     {
         this._headerElement = document.createElement("h1");
         this._headerElement.textContent = WebInspector.UIString("Select audits to run");
+
+        for (var child = 0; child < this._contentElement.children.length; ++child)
+            this._contentElement.removeChild(this._contentElement.children[child]);
+
         this._contentElement.appendChild(this._headerElement);
 
         function handleSelectAllClick(event)
@@ -204,16 +222,6 @@ WebInspector.AuditLauncherView.prototype = {
         this._categoriesElement.className = "audit-categories-container";
         this._contentElement.appendChild(this._categoriesElement);
 
-        var boundCategoryClickListener = this._categoryClicked.bind(this);
-
-        for (var i = 0; i < sortedCategories.length; ++i) {
-            categoryElement = this._createCategoryElement(sortedCategories[i].displayName, sortedCategories[i].id);
-            categoryElement.firstChild.addEventListener("click", boundCategoryClickListener, false);
-            sortedCategories[i]._checkboxElement = categoryElement.firstChild;
-            this._categoriesElement.appendChild(categoryElement);
-        }
-
-        this._totalCategoriesCount = this._categoriesElement.childNodes.length;
         this._currentCategoriesCount = 0;
 
         var flexibleSpaceElement = document.createElement("div");
diff --git a/WebCore/inspector/front-end/AuditResultView.js b/WebCore/inspector/front-end/AuditResultView.js
index 2f4afbd..2636463 100644
--- a/WebCore/inspector/front-end/AuditResultView.js
+++ b/WebCore/inspector/front-end/AuditResultView.js
@@ -81,15 +81,22 @@ WebInspector.AuditCategoryResultPane = function(categoryResult)
 WebInspector.AuditCategoryResultPane.prototype = {
     _appendResult: function(parentTreeElement, result)
     {
-        var title = result.value;
-        if (result.violationCount)
-            title = String.sprintf("%s (%d)", title, result.violationCount);
+        var title = "";
+        
+        if (typeof result.value === "string") {
+            title = result.value;
+            if (result.violationCount)
+                title = String.sprintf("%s (%d)", title, result.violationCount);
+        }
 
         var treeElement = new TreeElement(title, null, !!result.children);
         parentTreeElement.appendChild(treeElement);
 
         if (result.className)
             treeElement.listItemElement.addStyleClass(result.className);
+        if (typeof result.value !== "string")
+            treeElement.listItemElement.appendChild(WebInspector.applyFormatters(result.value));
+
         if (result.children) {
             for (var i = 0; i < result.children.length; ++i)
                 this._appendResult(treeElement, result.children[i]);
diff --git a/WebCore/inspector/front-end/AuditsPanel.js b/WebCore/inspector/front-end/AuditsPanel.js
index bc7f3b3..f6cbed0 100644
--- a/WebCore/inspector/front-end/AuditsPanel.js
+++ b/WebCore/inspector/front-end/AuditsPanel.js
@@ -32,8 +32,6 @@ WebInspector.AuditsPanel = function()
 {
     WebInspector.Panel.call(this, "audits");
 
-    this._constructCategories();
-
     this.createSidebar();
     this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true);
     this.sidebarTree.appendChild(this.auditsTreeElement);
@@ -54,7 +52,11 @@ WebInspector.AuditsPanel = function()
     this.viewsContainerElement.id = "audit-views";
     this.element.appendChild(this.viewsContainerElement);
 
-    this._launcherView = new WebInspector.AuditLauncherView(this.categoriesById, this.initiateAudit.bind(this));
+    this._constructCategories();
+
+    this._launcherView = new WebInspector.AuditLauncherView(this.initiateAudit.bind(this));
+    for (id in this.categoriesById)
+        this._launcherView.addCategory(this.categoriesById[id]);
 }
 
 WebInspector.AuditsPanel.prototype = {
@@ -104,6 +106,17 @@ WebInspector.AuditsPanel.prototype = {
         this._launcherView.resourceFinished(resource);
     },
 
+    addCategory: function(category)
+    {
+        this.categoriesById[category.id] = category;
+        this._launcherView.addCategory(category);
+    },
+
+    getCategory: function(id)
+    {
+        return this.categoriesById[id];
+    },
+
     _constructCategories: function()
     {
         this._auditCategoriesById = {};
@@ -147,7 +160,7 @@ WebInspector.AuditsPanel.prototype = {
             var category = categories[i];
             var result = new WebInspector.AuditCategoryResult(category);
             results.push(result);
-            category.runRules(resources, ruleResultReadyCallback.bind(null, result));
+            category.run(resources, ruleResultReadyCallback.bind(null, result));
         }
     },
 
@@ -220,7 +233,7 @@ WebInspector.AuditsPanel.prototype = {
     {
         this.visibleView = this._launcherView;
     },
-    
+
     get visibleView()
     {
         return this._visibleView;
@@ -311,7 +324,7 @@ WebInspector.AuditCategory.prototype = {
         this._rules.push(rule);
     },
 
-    runRules: function(resources, callback)
+    run: function(resources, callback)
     {
         this._ensureInitialized();
         for (var i = 0; i < this._rules.length; ++i)
diff --git a/WebCore/inspector/front-end/ExtensionAPI.js b/WebCore/inspector/front-end/ExtensionAPI.js
index a89dcf1..9d996bf 100644
--- a/WebCore/inspector/front-end/ExtensionAPI.js
+++ b/WebCore/inspector/front-end/ExtensionAPI.js
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
+WebInspector.injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
 {
 
 // Here and below, all constructors are private to API implementation.
@@ -37,19 +37,22 @@ var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injecte
 // by Foo consutrctor to re-bind publicly exported members to an instance
 // of Foo.
 
-function EventSinkImpl(type)
+function EventSinkImpl(type, customDispatch)
 {
     this._type = type;
     this._listeners = [];
+    this._customDispatch = customDispatch;
 }
 
 EventSinkImpl.prototype = {
     addListener: function(callback)
     {
+        if (typeof callback != "function")
+            throw new "addListener: callback is not a function";
         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));
+        extensionServer.registerHandler("notify-" + this._type, bind(this._dispatch, this));
     },
 
     removeListener: function(callback)
@@ -66,26 +69,36 @@ EventSinkImpl.prototype = {
             extensionServer.sendRequest({ command: "unsubscribe", type: this._type });
     },
 
-    _fire: function(request)
+    _fire: function()
     {
         var listeners = this._listeners.slice();
         for (var i = 0; i < listeners.length; ++i)
-            listeners[i].apply(null, request.arguments);
+            listeners[i].apply(null, arguments);
+    },
+
+    _dispatch: function(request)
+    {
+         if (this._customDispatch)
+             this._customDispatch.call(this, request);
+         else
+             this._fire.apply(this, request.arguments);
     }
 }
 
-function EventSink(type)
+function EventSink(type, customDispatch)
 {
-    var impl = new EventSinkImpl(type);
+    var impl = new EventSinkImpl(type, customDispatch);
     this.addListener = bind(impl.addListener, impl);
     this.removeListener = bind(impl.removeListener, impl);
 }
 
 function InspectorExtensionAPI()
 {
+    this.audits = new Audits();
     this.inspectedWindow = new InspectedWindow();
     this.panels = new Panels();
     this.resources = new Resources();
+
     this.onReset = new EventSink("reset");
 }
 
@@ -125,7 +138,7 @@ function Panels()
     {
         return panels[name];
     }
-    
+
     for (var i = 0; i < wellKnownPanelNames.length; ++i) {
         var name = wellKnownPanelNames[i];
         panels[name] = new Panel(name);
@@ -151,7 +164,7 @@ Panels.prototype = {
             id: id,
             label: label,
             url: expandURL(pageURL),
-            icon: expandURL(iconURL) 
+            icon: expandURL(iconURL)
         };
         extensionServer.sendRequest(request, callback && bind(callbackWrapper, this));
     }
@@ -219,6 +232,124 @@ function ExtensionSidebarPane(id)
     this.setExpanded = bind(impl.setExpanded, impl);
 }
 
+function Audits()
+{
+}
+
+Audits.prototype = {
+    addCategory: function(displayName, ruleCount)
+    {
+        var id = "extension-audit-category-" + extensionServer.nextObjectId();
+        extensionServer.sendRequest({ command: "addAuditCategory", id: id, displayName: displayName, ruleCount: ruleCount });
+        return new AuditCategory(id);
+    }
+}
+
+function AuditCategory(id)
+{
+    function customDispatch(request)
+    {
+        var auditResult = new AuditResult(request.arguments[0]);
+        try {
+            this._fire(auditResult);
+        } catch (e) {
+            console.error("Uncaught exception in extension audit event handler: " + e);
+            auditResult.done();
+        }
+    }
+    var impl = new AuditCategoryImpl(id);
+    this.onAuditStarted = new EventSink("audit-started-" + id, customDispatch);
+}
+
+function AuditCategoryImpl(id)
+{
+    this._id = id;
+}
+
+function AuditResult(id)
+{
+    var impl = new AuditResultImpl(id);
+
+    this.addResult = bind(impl.addResult, impl);
+    this.createResult = bind(impl.createResult, impl);
+    this.done = bind(impl.done, impl);
+
+    var formatterTypes = [
+        "url",
+        "snippet",
+        "text"
+    ];
+    for (var i = 0; i < formatterTypes.length; ++i)
+        this[formatterTypes[i]] = bind(impl._nodeFactory, null, formatterTypes[i]);
+}
+
+AuditResult.prototype = {
+    get Severity()
+    {
+        return private.audits.Severity;
+    }
+}
+
+function AuditResultImpl(id)
+{
+    this._id = id;
+}
+
+AuditResultImpl.prototype = {
+    addResult: function(displayName, description, severity, details)
+    {
+        // shorthand for specifying details directly in addResult().
+        if (details && !(details instanceof AuditResultNode))
+            details = details instanceof Array ? this.createNode.apply(this, details) : this.createNode(details);
+
+        var request = {
+            command: "addAuditResult",
+            resultId: this._id,
+            displayName: displayName,
+            description: description,
+            severity: severity,
+            details: details
+        };
+        extensionServer.sendRequest(request);
+    },
+
+    createResult: function()
+    {
+        var node = new AuditResultNode();
+        node.contents = Array.prototype.slice.call(arguments);
+        return node;
+    },
+
+    done: function()
+    {
+        extensionServer.sendRequest({ command: "stopAuditCategoryRun", resultId: this._id });
+    },
+
+    _nodeFactory: function(type)
+    {
+        return {
+            type: type,
+            arguments: Array.prototype.slice.call(arguments, 1)
+        };
+    }
+}
+
+function AuditResultNode(contents)
+{
+    this.contents = contents;
+    this.children = [];
+    this.expanded = false;
+}
+
+AuditResultNode.prototype = {
+    addChild: function()
+    {
+        var node = AuditResultImpl.prototype.createResult.apply(null, arguments);
+        this.children.push(node);
+        return node;
+    }
+};
+
 function InspectedWindow()
 {
     this.onLoaded = new EventSink("inspectedPageLoaded");
diff --git a/WebCore/inspector/front-end/ExtensionAuditCategory.js b/WebCore/inspector/front-end/ExtensionAuditCategory.js
new file mode 100644
index 0000000..5d155d7
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionAuditCategory.js
@@ -0,0 +1,111 @@
+/*
+ * 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.ExtensionAuditCategory = function(id, displayName, ruleCount)
+{
+    this._id = id;
+    this._displayName = displayName;
+    this._ruleCount  = ruleCount;
+}
+
+WebInspector.ExtensionAuditCategory.prototype = {
+    // AuditCategory interface
+    get id()
+    {
+        return this._id;
+    },
+
+    get displayName()
+    {
+        return this._displayName;
+    },
+
+    get ruleCount()
+    {
+        return this._ruleCount;
+    },
+
+    run: function(resources, callback)
+    {
+        new WebInspector.ExtensionAuditCategoryResults(this, callback);
+    }
+}
+
+WebInspector.ExtensionAuditCategoryResults = function(category, callback)
+{
+    this._category = category;
+    this._pendingRules = category.ruleCount;
+    this._ruleCompletionCallback = callback;
+
+    this.id = category.id + "-" + ++WebInspector.ExtensionAuditCategoryResults._lastId;
+    WebInspector.extensionServer.startAuditRun(category, this);
+}
+
+WebInspector.ExtensionAuditCategoryResults.prototype = {
+    get complete()
+    {
+        return !this._pendingRules;
+    },
+
+    cancel: function()
+    {
+        while (!this.complete)
+            this._addResult(null);
+    },
+
+    addResult: function(displayName, description, severity, details)
+    {
+        var result = new WebInspector.AuditRuleResult(displayName);
+        result.addChild(description);
+        result.severity = severity;
+        if (details)
+            this._addNode(result, details);
+        this._addResult(result);
+    },
+
+    _addNode: function(parent, node)
+    {
+        var addedNode = parent.addChild(node.contents, node.expanded);
+        if (node.children) {
+            for (var i = 0; i < node.children.length; ++i)
+                this._addNode(addedNode, node.children[i]);
+        }
+    },
+
+    _addResult: function(result)
+    {
+        this._ruleCompletionCallback(result);
+        this._pendingRules--;
+        if (!this._pendingRules)
+            WebInspector.extensionServer.stopAuditRun(this);
+    }
+}
+
+WebInspector.ExtensionAuditCategoryResults._lastId = 0;
diff --git a/WebCore/inspector/front-end/ExtensionCommon.js b/WebCore/inspector/front-end/ExtensionCommon.js
new file mode 100644
index 0000000..b04c18c
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionCommon.js
@@ -0,0 +1,46 @@
+/*
+ * 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.commonExtensionSymbols = function(private)
+{
+    
+    if (!private.audits)
+        private.audits = {};
+
+    private.audits.Severity = {
+        Info: "info",
+        Warning: "warning",
+        Severe: "severe"
+    };
+}
+
+WebInspector.extensionAPI = {};
+
+WebInspector.commonExtensionSymbols(WebInspector.extensionAPI);
diff --git a/WebCore/inspector/front-end/ExtensionServer.js b/WebCore/inspector/front-end/ExtensionServer.js
index 95f373f..0ff035c 100644
--- a/WebCore/inspector/front-end/ExtensionServer.js
+++ b/WebCore/inspector/front-end/ExtensionServer.js
@@ -40,11 +40,15 @@ WebInspector.ExtensionServer = function()
     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("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));
 
+    this._registerHandler("addAuditCategory", this._onAddAuditCategory.bind(this));
+    this._registerHandler("addAuditResult", this._onAddAuditResult.bind(this));
+    this._registerHandler("stopAuditCategoryRun", this._onStopAuditCategoryRun.bind(this));
+
     window.addEventListener("message", this._onWindowMessage.bind(this), false);
 }
 
@@ -84,6 +88,17 @@ WebInspector.ExtensionServer.prototype = {
         this._postNotification("reset");
     },
 
+    startAuditRun: function(category, auditRun)
+    {
+        this._clientObjects[auditRun.id] = auditRun;
+        this._postNotification("audit-started-" + category.id, auditRun.id);
+    },
+
+    stopAuditRun: function(auditRun)
+    {
+        delete this._clientObjects[auditRun.id];
+    },
+
     _convertResource: function(resource)
     {
         return {
@@ -100,7 +115,7 @@ WebInspector.ExtensionServer.prototype = {
             return;
         var message = {
             command: "notify-" + type,
-            arguments: Array.prototype.slice.call(arguments, 1) 
+            arguments: Array.prototype.slice.call(arguments, 1)
         };
         for (var i = 0; i < subscribers.length; ++i)
             subscribers[i].postMessage(message);
@@ -248,6 +263,36 @@ WebInspector.ExtensionServer.prototype = {
         return response;
     },
 
+    _onAddAuditCategory: function(request)
+    {
+        var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.ruleCount);
+        if (WebInspector.panels.audits.getCategory(category.id))
+            return this._status.E_EXISTS(category.id);
+        this._clientObjects[request.id] = category;
+        WebInspector.panels.audits.addCategory(category);
+    },
+
+    _onAddAuditResult: function(request)
+    {
+        var auditResult = this._clientObjects[request.resultId];
+        if (!auditResult)
+            return this._status.E_NOTFOUND(request.resultId);
+        try {
+            auditResult.addResult(request.displayName, request.description, request.severity, request.details);
+        } catch (e) {
+            return e;
+        }
+        return this._status.OK();
+    },
+
+    _onStopAuditCategoryRun: function(request)
+    {
+        var auditRun = this._clientObjects[request.resultId];
+        if (!auditRun)
+            return this._status.E_NOTFOUND(request.resultId);
+        auditRun.cancel();
+    },
+
     initExtensions: function()
     {
         InspectorExtensionRegistry.getExtensionsAsync();
@@ -255,7 +300,8 @@ WebInspector.ExtensionServer.prototype = {
 
     _addExtensions: function(extensions)
     {
-        InspectorFrontendHost.setExtensionAPI("(" + injectedExtensionAPI.toString() + ")"); // See ExtensionAPI.js for details.
+        // See ExtensionAPI.js and ExtensionCommon.js for details.
+        InspectorFrontendHost.setExtensionAPI(this._buildExtensionAPIInjectedScript());
         for (var i = 0; i < extensions.length; ++i) {
             var extension = extensions[i];
             try {
@@ -271,6 +317,15 @@ WebInspector.ExtensionServer.prototype = {
         }
     },
 
+    _buildExtensionAPIInjectedScript: function()
+    {
+        return "(function(){ " +
+            "var private = {};" +
+            "(" + WebInspector.commonExtensionSymbols.toString() + ")(private);" +
+            "(" + WebInspector.injectedExtensionAPI.toString() + ").apply(this, arguments);" +
+            "})";
+    },
+
     _onWindowMessage: function(event)
     {
         if (event.data !== "registerExtension")
@@ -300,12 +355,14 @@ WebInspector.ExtensionServer.prototype = {
     }
 }
 
-WebInspector.ExtensionServer._statuses = 
+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)"
+    E_EXISTS: "Object already exists: %s",
+    E_BADARG: "Invalid argument %s: %s",
+    E_BADARGTYPE: "Invalid type for argument %s: got %s, expected %s",
+    E_NOTFOUND: "Object not found: %s",
+    E_NOTSUPPORTED: "Object does not support requested operation: %s",
 }
 
 WebInspector.ExtensionStatus = function()
@@ -319,7 +376,7 @@ WebInspector.ExtensionStatus = function()
             status.isError = true;
             console.log("Extension server error: " + String.vsprintf(description, details));
         }
-        return status; 
+        return status;
     }
     for (status in WebInspector.ExtensionServer._statuses)
         this[status] = makeStatus.bind(null, status);
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index 1f15db3..b640936 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -4,6 +4,7 @@
     <file>AbstractTimelinePanel.js</file>
     <file>ApplicationCacheItemsView.js</file>
     <file>AuditCategories.js</file>
+    <file>AuditFormatters.js</file>
     <file>AuditLauncherView.js</file>
     <file>AuditResultView.js</file>
     <file>AuditRules.js</file>
@@ -35,6 +36,8 @@
     <file>ElementsTreeOutline.js</file>
     <file>EventListenersSidebarPane.js</file>
     <file>ExtensionAPI.js</file>
+    <file>ExtensionAuditCategory.js</file>
+    <file>ExtensionCommon.js</file>
     <file>ExtensionPanel.js</file>
     <file>ExtensionRegistryStub.js</file>
     <file>ExtensionServer.js</file>
diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
index 4968685..3e4b6c1 100644
--- a/WebCore/inspector/front-end/inspector.html
+++ b/WebCore/inspector/front-end/inspector.html
@@ -98,6 +98,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <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="ExtensionAuditCategory.js"></script>
+    <script type="text/javascript" src="ExtensionCommon.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>
@@ -105,6 +107,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="AuditLauncherView.js"></script>
     <script type="text/javascript" src="AuditRules.js"></script>
     <script type="text/javascript" src="AuditCategories.js"></script>
+    <script type="text/javascript" src="AuditFormatters.js"></script>
     <script type="text/javascript" src="ResourceView.js"></script>
     <script type="text/javascript" src="SourceFrame.js"></script>
     <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script>
diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js
index 66cf284..e8adff6 100644
--- a/WebCore/inspector/front-end/utilities.js
+++ b/WebCore/inspector/front-end/utilities.js
@@ -732,12 +732,6 @@ Array.convert = function(list)
 
 function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction)
 {
-    // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound.
-    return (-indexOfObjectInListSortedByFunction(anObject, aList, aFunction) - 1);
-}
-
-function indexOfObjectInListSortedByFunction(anObject, aList, aFunction)
-{
     var first = 0;
     var last = aList.length - 1;
     var floor = Math.floor;
@@ -760,9 +754,7 @@ function indexOfObjectInListSortedByFunction(anObject, aList, aFunction)
         }
     }
 
-    // By returning 1 less than the negative lower search bound, we can reuse this function
-    // for both indexOf and insertionIndexFor, with some simple arithmetic.
-    return (-first - 1);
+    return first;
 }
 
 String.sprintf = function(format)

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list