[Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Nov 2020 00:03:43 +0000 (00:03 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Nov 2020 00:03:43 +0000 (00:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=217783
<rdar://problem/69968787>

Reviewed by Devin Rousso.

Source/WebCore:

* inspector/InspectorFrontendClient.h:
* inspector/InspectorFrontendClientLocal.h:
In order for WebInspectorUIExtensionController to work with remote and local
inspectors, it stores a weak pointer the inspector's InspectorFrontendClient.
Expose the frontend's page so that the frontend API dispatcher can dispatch to it.

Source/WebInspectorUI:

* UserInterface/Main.html: Add new files.

* UserInterface/Controllers/AppControllerBase.js:
(WI.AppControllerBase):
(WI.AppControllerBase.prototype.get extensionController):
Hang the extension controller off of the global singleton, as there can only be one.

* UserInterface/Controllers/WebInspectorExtensionController.js:
(WI.WebInspectorExtensionController):
(WI.WebInspectorExtensionController.prototype.registerExtension):
(WI.WebInspectorExtensionController.prototype.unregisterExtension):
Added. For now, just keep the UUIDs in a map and log the result.

* UserInterface/Models/WebInspectorExtension.js:
(WI.WebInspectorExtension):
(WI.WebInspectorExtension.prototype.get extensionID):
(WI.WebInspectorExtension.prototype.get displayName):
Added. This is a data object for now.

* UserInterface/Protocol/InspectorFrontendAPI.js:
(InspectorFrontendAPI.loadCompleted):
(InspectorFrontendAPI.registerExtension):
(InspectorFrontendAPI.unregisterExtension):
Added. Forward invocations to the extension controller.

Source/WebKit:

_WKInspectorExtension is new SPI that represents a Web Extension that uses the 'devtools'
API to interact with Web Inspector. An extension is associated with its _WKInspectorExtensionHost.
A WebKit client that supports Web Extensions can use this class to implement 'devtools' extension APIs.

Add _WKInspectorExtensionHost methods to register and unregister an extension.
Add plumbing so that the extension in registered in the frontend with WI.InspectorExtensionController.

Later patches will flesh out the needed functionality to implement rest of the 'devtools' API.

* Sources.txt:
* SourcesCocoa.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* WebKit.xcodeproj/project.pbxproj:
Add new files.

* Scripts/webkit/messages.py: If a message includes InspectorExtensionError,
then generate an include for InspectorExtensionTypes.h where it is declared.

* Shared/API/APIObject.h:
* Shared/Cocoa/APIObject.mm:
(API::Object::newObject):
New API object type.

* Shared/InspectorExtensionTypes.h: Added error code enum and useful type aliases.
* Shared/InspectorExtensionTypes.cpp:
(WebKit::inspectorExtensionErrorToString):

* UIProcess/API/APIInspectorExtension.h:
* UIProcess/API/APIInspectorExtension.cpp:
(API::InspectorExtension::create):
(API::InspectorExtension::InspectorExtension):
(API::InspectorExtension::~InspectorExtension):
Added. This is a placeholder object that's used for the wrapper system,
since we don't have single C++ objects for each extension to back the API object.

* UIProcess/API/Cocoa/_WKInspector.h:
* UIProcess/API/Cocoa/_WKInspector.mm:
(-[_WKInspector registerExtensionWithID:displayName:completionHandler:]):
(-[_WKInspector unregisterExtension:completionHandler:]):
Implement new _WKInspectorExtensionHost methods. Send IPC to the Inspector web process.

* UIProcess/API/Cocoa/_WKInspectorExtension.h:
* UIProcess/API/Cocoa/_WKInspectorExtension.mm:
(-[_WKInspectorExtension initWithIdentifier:]):
(-[_WKInspectorExtension dealloc]):
(-[_WKInspectorExtension _apiObject]):
(-[_WKInspectorExtension extensionID]):
Added. This is a data object that's also used as a token to unregister the extension.

* UIProcess/API/Cocoa/_WKInspectorExtensionHost.h: Add new SPI.
* UIProcess/API/Cocoa/_WKInspectorExtensionInternal.h:

* UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.h:
* UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm:
(-[_WKRemoteWebInspectorViewController registerExtensionWithID:displayName:completionHandler:]):
(-[_WKRemoteWebInspectorViewController unregisterExtension:completionHandler:]):
Implement new _WKInspectorExtensionHost methods. Send IPC to the Inspector web process.

* UIProcess/Inspector/RemoteWebInspectorProxy.h:
* UIProcess/Inspector/RemoteWebInspectorProxy.messages.in: Add FrontendLoaded.
(WebKit::RemoteWebInspectorProxy::extensionController const): Added.
* UIProcess/Inspector/RemoteWebInspectorProxy.cpp:
(WebKit::RemoteWebInspectorProxy::frontendLoaded):
(WebKit::RemoteWebInspectorProxy::createFrontendPageAndWindow):
Set up the extension controller object after the frontend has been created.
Hook up the FrontendLoaded event sent from Inspector web process so that the
extension controller can be notified of when it's safe to message the frontend.

* UIProcess/Inspector/WebInspectorProxy.cpp:
(WebKit::WebInspectorProxy::createFrontendPage):
(WebKit::WebInspectorProxy::closeFrontendPageAndWindow):
(WebKit::WebInspectorProxy::frontendLoaded):
Set up the extension controller object after the frontend has been created.

* UIProcess/Inspector/WebInspectorProxy.h:
(WebKit::WebInspectorProxy::extensionController const): Added.

* UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h:
* UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp: Added.
(WebKit::WebInspectorUIExtensionControllerProxy::WebInspectorUIExtensionControllerProxy):
(WebKit::WebInspectorUIExtensionControllerProxy::~WebInspectorUIExtensionControllerProxy):
(WebKit::WebInspectorUIExtensionControllerProxy::whenFrontendHasLoaded):
(WebKit::WebInspectorUIExtensionControllerProxy::inspectorFrontendLoaded):
(WebKit::WebInspectorUIExtensionControllerProxy::registerExtension):
(WebKit::WebInspectorUIExtensionControllerProxy::unregisterExtension):
Added. Forward API requests to the Web Inspector's web process to be evaluated in the frontend.

* WebProcess/Inspector/WebInspectorFrontendAPIDispatcher.h:
* WebProcess/Inspector/WebInspectorFrontendAPIDispatcher.cpp:
(WebKit::WebInspectorFrontendAPIDispatcher::dispatchCommand):
Add a more generic way to encode values to be passed as arguments to InspectorFrontendAPI.dispatch.

* WebProcess/Inspector/WebInspectorUI.cpp:
(WebKit::WebInspectorUI::establishConnection):
(WebKit::WebInspectorUI::closeWindow):
* WebProcess/Inspector/WebInspectorUI.h:
(WebKit::WebInspectorUI::frontendPage const): Added.
(WebKit::WebInspectorUI::frontendAPIDispatcher): Added.

* WebProcess/Inspector/WebInspectorUIExtensionController.h:
* WebProcess/Inspector/WebInspectorUIExtensionController.messages.in: Added.
* WebProcess/Inspector/WebInspectorUIExtensionController.cpp: Added.
(WebKit::WebInspectorUIExtensionController::WebInspectorUIExtensionController):
(WebKit::WebInspectorUIExtensionController::~WebInspectorUIExtensionController):
(WebKit::WebInspectorUIExtensionController::registerExtension):
(WebKit::WebInspectorUIExtensionController::unregisterExtension):
(WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromResult):
Handle incoming messages by forwarding the associated command to WI.WebExtensionController
via InspectorFrontendAPI evaluations.

* UIProcess/API/Cocoa/_WKUserStyleSheet.h:
* UIProcess/API/Cocoa/_WKUserStyleSheet.mm:
Fallout from unified build chunking shifts.

* UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
(WebKit::LocalAuthenticatorInternal::getExistingCredentials):
(WebKit::LocalAuthenticator::continueMakeCredentialAfterUserVerification):
Fallout from unified build chunking shifts, but more.

Tools:

Add API tests to exercise new methods of the _WKInspectorExtensionHost protocol.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: New test file.
* TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionHost.mm: Added.
(resetGlobalState):
(-[UIDelegateForTestingInspectorExtensionHost _webView:didAttachLocalInspector:]):
(TEST):

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

49 files changed:
Source/WebCore/ChangeLog
Source/WebCore/inspector/InspectorFrontendClient.h
Source/WebCore/inspector/InspectorFrontendClientLocal.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Controllers/AppControllerBase.js
Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/WebInspectorExtension.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebKit/ChangeLog
Source/WebKit/DerivedSources-input.xcfilelist
Source/WebKit/DerivedSources-output.xcfilelist
Source/WebKit/DerivedSources.make
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/Shared/API/APIObject.h
Source/WebKit/Shared/Cocoa/APIObject.mm
Source/WebKit/Shared/InspectorExtensionTypes.cpp [new file with mode: 0644]
Source/WebKit/Shared/InspectorExtensionTypes.h [new file with mode: 0644]
Source/WebKit/Sources.txt
Source/WebKit/SourcesCocoa.txt
Source/WebKit/UIProcess/API/APIInspectorExtension.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKInspector.h
Source/WebKit/UIProcess/API/Cocoa/_WKInspector.mm
Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionHost.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionInternal.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.h
Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm
Source/WebKit/UIProcess/Inspector/RemoteWebInspectorProxy.cpp
Source/WebKit/UIProcess/Inspector/RemoteWebInspectorProxy.h
Source/WebKit/UIProcess/Inspector/RemoteWebInspectorProxy.messages.in
Source/WebKit/UIProcess/Inspector/WebInspectorProxy.cpp
Source/WebKit/UIProcess/Inspector/WebInspectorProxy.h
Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/Inspector/RemoteWebInspectorUI.cpp
Source/WebKit/WebProcess/Inspector/RemoteWebInspectorUI.h
Source/WebKit/WebProcess/Inspector/WebInspectorUI.cpp
Source/WebKit/WebProcess/Inspector/WebInspectorUI.h
Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h [new file with mode: 0644]
Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in [new file with mode: 0644]
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionHost.mm [new file with mode: 0644]

index 15181b2..75e25ed 100644 (file)
@@ -1,3 +1,17 @@
+2020-11-05  Brian Burg  <bburg@apple.com>
+
+        [Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
+        https://bugs.webkit.org/show_bug.cgi?id=217783
+        <rdar://problem/69968787>
+
+        Reviewed by Devin Rousso.
+
+        * inspector/InspectorFrontendClient.h:
+        * inspector/InspectorFrontendClientLocal.h:
+        In order for WebInspectorUIExtensionController to work with remote and local
+        inspectors, it stores a weak pointer the inspector's InspectorFrontendClient.
+        Expose the frontend's page so that the frontend API dispatcher can dispatch to it.
+
 2020-11-05  Chris Dumez  <cdumez@apple.com>
 
         Add implementation for Object.getOwnPropertyNames() on HTMLDocument
index 0a79d86..e8d13a2 100644 (file)
 #include "InspectorDebuggableType.h"
 #include "UserInterfaceLayoutDirection.h"
 #include <wtf/Forward.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
 class FloatRect;
 class InspectorFrontendAPIDispatcher;
+class Page;
 
-class InspectorFrontendClient {
+class InspectorFrontendClient : public CanMakeWeakPtr<InspectorFrontendClient> {
 public:
     enum class DockSide {
         Undocked = 0,
@@ -111,6 +113,7 @@ public:
 
     WEBCORE_EXPORT virtual void sendMessageToBackend(const String&) = 0;
     WEBCORE_EXPORT virtual InspectorFrontendAPIDispatcher& frontendAPIDispatcher() = 0;
+    WEBCORE_EXPORT virtual Page* frontendPage() = 0;
 
     WEBCORE_EXPORT virtual bool isUnderTest() = 0;
 };
index 1181a20..ad18f60 100644 (file)
@@ -95,7 +95,8 @@ public:
     String backendCommandsURL() const final { return String(); };
 
     InspectorFrontendAPIDispatcher& frontendAPIDispatcher() final { return m_frontendAPIDispatcher; }
-
+    Page* frontendPage() final { return m_frontendPage; }
+    
     WEBCORE_EXPORT bool canAttachWindow();
     WEBCORE_EXPORT void setDockingUnavailable(bool);
 
index 1c6461a..bcbd2fd 100644 (file)
@@ -1,3 +1,36 @@
+2020-11-05  Brian Burg  <bburg@apple.com>
+
+        [Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
+        https://bugs.webkit.org/show_bug.cgi?id=217783
+        <rdar://problem/69968787>
+
+        Reviewed by Devin Rousso.
+
+        * UserInterface/Main.html: Add new files.
+
+        * UserInterface/Controllers/AppControllerBase.js:
+        (WI.AppControllerBase):
+        (WI.AppControllerBase.prototype.get extensionController):
+        Hang the extension controller off of the global singleton, as there can only be one.
+
+        * UserInterface/Controllers/WebInspectorExtensionController.js:
+        (WI.WebInspectorExtensionController):
+        (WI.WebInspectorExtensionController.prototype.registerExtension):
+        (WI.WebInspectorExtensionController.prototype.unregisterExtension):
+        Added. For now, just keep the UUIDs in a map and log the result.
+
+        * UserInterface/Models/WebInspectorExtension.js:
+        (WI.WebInspectorExtension):
+        (WI.WebInspectorExtension.prototype.get extensionID):
+        (WI.WebInspectorExtension.prototype.get displayName):
+        Added. This is a data object for now.
+
+        * UserInterface/Protocol/InspectorFrontendAPI.js:
+        (InspectorFrontendAPI.loadCompleted):
+        (InspectorFrontendAPI.registerExtension):
+        (InspectorFrontendAPI.unregisterExtension):
+        Added. Forward invocations to the extension controller.
+
 2020-11-05  Patrick Angle  <pangle@apple.com>
 
         Web Inspector: REGRESSION(?): Sources: override banner is squished for large images
index 61d4c45..0025374 100644 (file)
@@ -41,11 +41,14 @@ WI.AppControllerBase = class AppControllerBase
     constructor()
     {
         this._initialized = false;
+
+        this._extensionController = new WI.WebInspectorExtensionController;
     }
 
     // Public
 
     get debuggableType() { throw WI.NotImplementedError.subclassMustOverride(); }
+    get extensionController() { return this._extensionController; }
 
     // Since various members of the app controller depend on the global singleton to exist,
     // some initialization needs to happen after the app controller has been constructed.
diff --git a/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js b/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js
new file mode 100644 (file)
index 0000000..02e396c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.WebInspectorExtensionController = class WebInspectorExtensionController extends WI.Object
+{
+    constructor()
+    {
+        super();
+
+        this._extensionIDMap = new Map;
+    }
+
+    // Public
+
+    registerExtension(extensionID, displayName)
+    {
+        if (this._extensionIDMap.has(extensionID)) {
+            WI.reportInternalError("Unable to register extension, it's already registered: ", extensionID, displayName);
+            return WI.WebInspectorExtension.ErrorCode.RegistrationFailed;
+        }
+
+        let extension = new WI.WebInspectorExtension(extensionID, displayName);
+        this._extensionIDMap.set(extensionID, extension);
+
+        this.dispatchEventToListeners(WI.WebInspectorExtensionController.Event.ExtensionAdded, {extension});
+    }
+
+    unregisterExtension(extensionID)
+    {
+        let extension = this._extensionIDMap.take(extensionID);
+        if (!extension) {
+            WI.reportInternalError("Unable to unregister extension with unknown ID: ", extensionID);
+            return WI.WebInspectorExtension.ErrorCode.InvalidRequest;
+        }
+
+        this.dispatchEventToListeners(WI.WebInspectorExtensionController.Event.ExtensionRemoved, {extension});
+    }
+};
+
+WI.WebInspectorExtensionController.Event = {
+    ExtensionAdded: "extension-added",
+    ExtensionRemoved: "extension-removed",
+};
index fae3cf8..b86df5f 100644 (file)
     <script src="Models/TypeDescription.js"></script>
     <script src="Models/TypeSet.js"></script>
     <script src="Models/URLBreakpoint.js"></script>
+    <script src="Models/WebInspectorExtension.js"></script>
     <script src="Models/WebSocketResource.js"></script>
     <script src="Models/WrappedPromise.js"></script>
 
     <script src="Controllers/TargetManager.js"></script>
     <script src="Controllers/TimelineManager.js"></script>
     <script src="Controllers/TypeTokenAnnotator.js"></script>
+    <script src="Controllers/WebInspectorExtensionController.js"></script>
     <script src="Controllers/WorkerManager.js"></script>
 
     <script src="Controllers/DiagnosticController.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/WebInspectorExtension.js b/Source/WebInspectorUI/UserInterface/Models/WebInspectorExtension.js
new file mode 100644 (file)
index 0000000..06d9eda
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.WebInspectorExtension = class WebInspectorExtension
+{
+    constructor(extensionID, displayName)
+    {
+        console.assert(typeof extensionID === "string", extensionID);
+        console.assert(typeof displayName === "string", displayName);
+
+        this._extensionID = extensionID;
+        this._displayName = displayName;
+    }
+
+    // Public
+
+    get extensionID() { return this._extensionID; }
+    get displayName() { return this._displayName; }
+};
+
+// Note: these values are synonymous with the values of enum class WebKit::InspectorExtensionError.
+WI.WebInspectorExtension.ErrorCode = {
+    ContextDestroyed: "ContextDestroyed",
+    InternalError: "InternalError",
+    InvalidRequest: "InvalidRequest",
+    RegistrationFailed: "RegistrationFailed",
+};
index 1d1f288..f9d20af 100644 (file)
@@ -196,5 +196,17 @@ InspectorFrontendAPI = {
             InspectorFrontendAPI.dispatch(InspectorFrontendAPI._pendingCommands[i]);
 
         delete InspectorFrontendAPI._pendingCommands;
-    }
+    },
+
+    // Returns a WI.WebInspectorExtension.ErrorCode if an error occurred, otherwise nothing.
+    registerExtension(extensionID, displayName)
+    {
+        return WI.sharedApp.extensionController.registerExtension(extensionID, displayName);
+    },
+
+    // Returns a WI.WebInspectorExtension.ErrorCode if an error occurred, otherwise nothing.
+    unregisterExtension(extensionID)
+    {
+        return WI.sharedApp.extensionController.unregisterExtension(extensionID);
+    },
 };
index 8b8462f..33324ac 100644 (file)
     <script src="Models/TimelineMarker.js"></script>
     <script src="Models/TimelineRecording.js"></script>
     <script src="Models/URLBreakpoint.js"></script>
+    <script src="Models/WebInspectorExtension.js"></script>
     <script src="Models/WebSocketResource.js"></script>
     <script src="Models/WrappedPromise.js"></script>
 
     <script src="Controllers/RuntimeManager.js"></script>
     <script src="Controllers/TargetManager.js"></script>
     <script src="Controllers/TimelineManager.js"></script>
+    <script src="Controllers/WebInspectorExtensionController.js"></script>
     <script src="Controllers/WorkerManager.js"></script>
 
     <script src="Controllers/ResourceQueryController.js"></script>
index 1e31141..6825a14 100644 (file)
@@ -1,3 +1,132 @@
+2020-11-05  Brian Burg  <bburg@apple.com>
+
+        [Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
+        https://bugs.webkit.org/show_bug.cgi?id=217783
+        <rdar://problem/69968787>
+
+        Reviewed by Devin Rousso.
+
+        _WKInspectorExtension is new SPI that represents a Web Extension that uses the 'devtools'
+        API to interact with Web Inspector. An extension is associated with its _WKInspectorExtensionHost.
+        A WebKit client that supports Web Extensions can use this class to implement 'devtools' extension APIs.
+
+        Add _WKInspectorExtensionHost methods to register and unregister an extension.
+        Add plumbing so that the extension in registered in the frontend with WI.InspectorExtensionController.
+
+        Later patches will flesh out the needed functionality to implement rest of the 'devtools' API.
+
+        * Sources.txt:
+        * SourcesCocoa.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * WebKit.xcodeproj/project.pbxproj:
+        Add new files.
+
+        * Scripts/webkit/messages.py: If a message includes InspectorExtensionError,
+        then generate an include for InspectorExtensionTypes.h where it is declared.
+
+        * Shared/API/APIObject.h:
+        * Shared/Cocoa/APIObject.mm:
+        (API::Object::newObject):
+        New API object type.
+
+        * Shared/InspectorExtensionTypes.h: Added error code enum and useful type aliases.
+        * Shared/InspectorExtensionTypes.cpp:
+        (WebKit::inspectorExtensionErrorToString):
+
+        * UIProcess/API/APIInspectorExtension.h:
+        * UIProcess/API/APIInspectorExtension.cpp:
+        (API::InspectorExtension::create):
+        (API::InspectorExtension::InspectorExtension):
+        (API::InspectorExtension::~InspectorExtension):
+        Added. This is a placeholder object that's used for the wrapper system,
+        since we don't have single C++ objects for each extension to back the API object.
+
+        * UIProcess/API/Cocoa/_WKInspector.h:
+        * UIProcess/API/Cocoa/_WKInspector.mm:
+        (-[_WKInspector registerExtensionWithID:displayName:completionHandler:]):
+        (-[_WKInspector unregisterExtension:completionHandler:]):
+        Implement new _WKInspectorExtensionHost methods. Send IPC to the Inspector web process.
+
+        * UIProcess/API/Cocoa/_WKInspectorExtension.h:
+        * UIProcess/API/Cocoa/_WKInspectorExtension.mm:
+        (-[_WKInspectorExtension initWithIdentifier:]):
+        (-[_WKInspectorExtension dealloc]):
+        (-[_WKInspectorExtension _apiObject]):
+        (-[_WKInspectorExtension extensionID]):
+        Added. This is a data object that's also used as a token to unregister the extension.
+
+        * UIProcess/API/Cocoa/_WKInspectorExtensionHost.h: Add new SPI.
+        * UIProcess/API/Cocoa/_WKInspectorExtensionInternal.h:
+
+        * UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.h:
+        * UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm:
+        (-[_WKRemoteWebInspectorViewController registerExtensionWithID:displayName:completionHandler:]):
+        (-[_WKRemoteWebInspectorViewController unregisterExtension:completionHandler:]):
+        Implement new _WKInspectorExtensionHost methods. Send IPC to the Inspector web process.
+
+        * UIProcess/Inspector/RemoteWebInspectorProxy.h:
+        * UIProcess/Inspector/RemoteWebInspectorProxy.messages.in: Add FrontendLoaded.
+        (WebKit::RemoteWebInspectorProxy::extensionController const): Added.
+        * UIProcess/Inspector/RemoteWebInspectorProxy.cpp:
+        (WebKit::RemoteWebInspectorProxy::frontendLoaded):
+        (WebKit::RemoteWebInspectorProxy::createFrontendPageAndWindow):
+        Set up the extension controller object after the frontend has been created.
+        Hook up the FrontendLoaded event sent from Inspector web process so that the
+        extension controller can be notified of when it's safe to message the frontend.
+
+        * UIProcess/Inspector/WebInspectorProxy.cpp:
+        (WebKit::WebInspectorProxy::createFrontendPage):
+        (WebKit::WebInspectorProxy::closeFrontendPageAndWindow):
+        (WebKit::WebInspectorProxy::frontendLoaded):
+        Set up the extension controller object after the frontend has been created.
+
+        * UIProcess/Inspector/WebInspectorProxy.h:
+        (WebKit::WebInspectorProxy::extensionController const): Added.
+
+        * UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h:
+        * UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp: Added.
+        (WebKit::WebInspectorUIExtensionControllerProxy::WebInspectorUIExtensionControllerProxy):
+        (WebKit::WebInspectorUIExtensionControllerProxy::~WebInspectorUIExtensionControllerProxy):
+        (WebKit::WebInspectorUIExtensionControllerProxy::whenFrontendHasLoaded):
+        (WebKit::WebInspectorUIExtensionControllerProxy::inspectorFrontendLoaded):
+        (WebKit::WebInspectorUIExtensionControllerProxy::registerExtension):
+        (WebKit::WebInspectorUIExtensionControllerProxy::unregisterExtension):
+        Added. Forward API requests to the Web Inspector's web process to be evaluated in the frontend.
+
+        * WebProcess/Inspector/WebInspectorFrontendAPIDispatcher.h:
+        * WebProcess/Inspector/WebInspectorFrontendAPIDispatcher.cpp:
+        (WebKit::WebInspectorFrontendAPIDispatcher::dispatchCommand):
+        Add a more generic way to encode values to be passed as arguments to InspectorFrontendAPI.dispatch.
+
+        * WebProcess/Inspector/WebInspectorUI.cpp:
+        (WebKit::WebInspectorUI::establishConnection):
+        (WebKit::WebInspectorUI::closeWindow):
+        * WebProcess/Inspector/WebInspectorUI.h:
+        (WebKit::WebInspectorUI::frontendPage const): Added.
+        (WebKit::WebInspectorUI::frontendAPIDispatcher): Added.
+
+        * WebProcess/Inspector/WebInspectorUIExtensionController.h:
+        * WebProcess/Inspector/WebInspectorUIExtensionController.messages.in: Added.
+        * WebProcess/Inspector/WebInspectorUIExtensionController.cpp: Added.
+        (WebKit::WebInspectorUIExtensionController::WebInspectorUIExtensionController):
+        (WebKit::WebInspectorUIExtensionController::~WebInspectorUIExtensionController):
+        (WebKit::WebInspectorUIExtensionController::registerExtension):
+        (WebKit::WebInspectorUIExtensionController::unregisterExtension):
+        (WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromResult):
+        Handle incoming messages by forwarding the associated command to WI.WebExtensionController
+        via InspectorFrontendAPI evaluations.
+
+        * UIProcess/API/Cocoa/_WKUserStyleSheet.h:
+        * UIProcess/API/Cocoa/_WKUserStyleSheet.mm:
+        Fallout from unified build chunking shifts.
+
+        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
+        (WebKit::LocalAuthenticatorInternal::getExistingCredentials):
+        (WebKit::LocalAuthenticator::continueMakeCredentialAfterUserVerification):
+        Fallout from unified build chunking shifts, but more.
+
 2020-11-05  Per Arne Vollan  <pvollan@apple.com>
 
         [macOS] Update message filters in the WebContent sandbox
index 6940fd4..ab15fbf 100644 (file)
@@ -95,6 +95,7 @@ $(PROJECT_DIR)/UIProcess/Downloads/DownloadProxy.messages.in
 $(PROJECT_DIR)/UIProcess/DrawingAreaProxy.messages.in
 $(PROJECT_DIR)/UIProcess/GPU/GPUProcessProxy.messages.in
 $(PROJECT_DIR)/UIProcess/Inspector/RemoteWebInspectorProxy.messages.in
+$(PROJECT_DIR)/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.messages.in
 $(PROJECT_DIR)/UIProcess/Inspector/WebInspectorProxy.messages.in
 $(PROJECT_DIR)/UIProcess/Media/AudioSessionRoutingArbitratorProxy.messages.in
 $(PROJECT_DIR)/UIProcess/Network/CustomProtocols/LegacyCustomProtocolManagerProxy.messages.in
@@ -142,6 +143,7 @@ $(PROJECT_DIR)/WebProcess/GPU/webrtc/SampleBufferDisplayLayer.messages.in
 $(PROJECT_DIR)/WebProcess/Geolocation/WebGeolocationManager.messages.in
 $(PROJECT_DIR)/WebProcess/Inspector/RemoteWebInspectorUI.messages.in
 $(PROJECT_DIR)/WebProcess/Inspector/WebInspector.messages.in
+$(PROJECT_DIR)/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in
 $(PROJECT_DIR)/WebProcess/Inspector/WebInspectorInterruptDispatcher.messages.in
 $(PROJECT_DIR)/WebProcess/Inspector/WebInspectorUI.messages.in
 $(PROJECT_DIR)/WebProcess/Network/NetworkProcessConnection.messages.in
index 82f6767..4eb125e 100644 (file)
@@ -348,6 +348,9 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebIDBConnectionToServerMessagesRep
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebIDBServerMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebIDBServerMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebIDBServerMessagesReplies.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebInspectorUIExtensionControllerMessageReceiver.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebInspectorUIExtensionControllerMessages.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebInspectorUIExtensionControllerMessagesReplies.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebInspectorInterruptDispatcherMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebInspectorInterruptDispatcherMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebInspectorInterruptDispatcherMessagesReplies.h
index 3c9879e..a76b396 100644 (file)
@@ -184,6 +184,7 @@ MESSAGE_RECEIVERS = \
        WebProcess/UserContent/WebUserContentController \
        WebProcess/Inspector/WebInspectorInterruptDispatcher \
        WebProcess/Inspector/WebInspectorUI \
+       WebProcess/Inspector/WebInspectorUIExtensionController \
        WebProcess/Inspector/WebInspector \
        WebProcess/Inspector/RemoteWebInspectorUI \
        WebProcess/Plugins/PluginProcessConnectionManager \
index 726872d..c1ae96c 100644 (file)
@@ -673,6 +673,7 @@ def headers_for_type(type):
         'WebKit::FindOptions': ['"WebFindOptions.h"'],
         'WebKit::GestureRecognizerState': ['"GestureTypes.h"'],
         'WebKit::GestureType': ['"GestureTypes.h"'],
+        'WebKit::InspectorExtensionError': ['"InspectorExtensionTypes.h"'],
         'WebKit::LayerHostingContextID': ['"LayerHostingContext.h"'],
         'WebKit::LayerHostingMode': ['"LayerTreeContext.h"'],
         'WebKit::PageState': ['"SessionState.h"'],
index 6d06564..b7b7ee6 100644 (file)
@@ -137,6 +137,9 @@ public:
         IconDatabase,
         Inspector,
         InspectorConfiguration,
+#if ENABLE(INSPECTOR_EXTENSIONS)
+        InspectorExtension,
+#endif
         KeyValueStorageManager,
         MediaCacheManager,
         MessageListener,
@@ -382,6 +385,9 @@ template<> struct EnumTraits<API::Object::Type> {
         API::Object::Type::IconDatabase,
         API::Object::Type::Inspector,
         API::Object::Type::InspectorConfiguration,
+#if ENABLE(INSPECTOR_EXTENSIONS)
+        API::Object::Type::InspectorExtension,
+#endif
         API::Object::Type::KeyValueStorageManager,
         API::Object::Type::MediaCacheManager,
         API::Object::Type::MessageListener,
index c9420cd..f8a028b 100644 (file)
 #import "_WKApplicationManifestInternal.h"
 #endif
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+#import "_WKInspectorExtensionInternal.h"
+#endif
+
 static const size_t minimumObjectAlignment = alignof(std::aligned_storage<std::numeric_limits<size_t>::max()>::type);
 static_assert(minimumObjectAlignment >= alignof(void*), "Objects should always be at least pointer-aligned.");
 static const size_t maximumExtraSpaceForAlignment = minimumObjectAlignment - alignof(void*);
@@ -270,6 +274,12 @@ void* Object::newObject(size_t size, Type type)
         wrapper = [_WKInspectorConfiguration alloc];
         break;
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    case Type::InspectorExtension:
+        wrapper = [_WKInspectorExtension alloc];
+        break;
+#endif
+
     case Type::Navigation:
         wrapper = [WKNavigation alloc];
         break;
diff --git a/Source/WebKit/Shared/InspectorExtensionTypes.cpp b/Source/WebKit/Shared/InspectorExtensionTypes.cpp
new file mode 100644 (file)
index 0000000..bf62d3d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorExtensionTypes.h"
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+WTF::String inspectorExtensionErrorToString(InspectorExtensionError error)
+{
+    switch (error) {
+    case InspectorExtensionError::InternalError:
+        return "InternalError"_s;
+    case InspectorExtensionError::InvalidRequest:
+        return "InvalidRequest"_s;
+    case InspectorExtensionError::ContextDestroyed:
+        return "ContextDestroyed"_s;
+    case InspectorExtensionError::RegistrationFailed:
+        return "RegistrationFailed"_s;
+    }
+
+    ASSERT_NOT_REACHED();
+    return "InternalError";
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
diff --git a/Source/WebKit/Shared/InspectorExtensionTypes.h b/Source/WebKit/Shared/InspectorExtensionTypes.h
new file mode 100644 (file)
index 0000000..ef3f5eb
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Forward.h>
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+namespace WebKit {
+
+using InspectorExtensionTabID = WTF::String;
+using InspectorExtensionID = WTF::String;
+
+enum class InspectorExtensionError : uint8_t {
+    ContextDestroyed,
+    InternalError,
+    InvalidRequest,
+    RegistrationFailed,
+};
+
+WTF::String inspectorExtensionErrorToString(InspectorExtensionError);
+
+} // namespace WebKit
+
+namespace WTF {
+
+template<> struct EnumTraits<WebKit::InspectorExtensionError> {
+    using values = EnumValues<
+        WebKit::InspectorExtensionError,
+        WebKit::InspectorExtensionError::InvalidRequest,
+        WebKit::InspectorExtensionError::ContextDestroyed,
+        WebKit::InspectorExtensionError::RegistrationFailed
+    >;
+};
+
+}
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
index d5279fe..351af42 100644 (file)
@@ -161,6 +161,7 @@ Shared/EditingRange.cpp
 Shared/EditorState.cpp
 Shared/FontInfo.cpp
 Shared/FrameInfoData.cpp
+Shared/InspectorExtensionTypes.cpp
 Shared/LayerTreeContext.cpp
 Shared/LoadParameters.cpp
 Shared/NavigationActionData.cpp
@@ -437,6 +438,7 @@ UIProcess/GPU/GPUProcessProxy.cpp
 UIProcess/Inspector/InspectorTargetProxy.cpp
 UIProcess/Inspector/RemoteWebInspectorProxy.cpp
 UIProcess/Inspector/WebInspectorProxy.cpp
+UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp
 UIProcess/Inspector/WebInspectorUtilities.cpp
 UIProcess/Inspector/WebPageDebuggable.cpp
 UIProcess/Inspector/WebPageInspectorController.cpp
@@ -550,6 +552,7 @@ WebProcess/Inspector/WebInspector.cpp
 WebProcess/Inspector/WebInspectorClient.cpp
 WebProcess/Inspector/WebInspectorInterruptDispatcher.cpp
 WebProcess/Inspector/WebInspectorUI.cpp
+WebProcess/Inspector/WebInspectorUIExtensionController.cpp
 WebProcess/Inspector/WebPageInspectorTarget.cpp
 WebProcess/Inspector/WebPageInspectorTargetController.cpp
 WebProcess/Inspector/WebPageInspectorTargetFrontendChannel.cpp
index 084d513..5d9b93d 100644 (file)
@@ -259,6 +259,7 @@ UIProcess/API/Cocoa/_WKInspector.mm
 UIProcess/API/Cocoa/_WKInspectorConfiguration.mm
 UIProcess/API/Cocoa/_WKInspectorTesting.mm
 UIProcess/API/Cocoa/_WKInspectorDebuggableInfo.mm
+UIProcess/API/Cocoa/_WKInspectorExtension.mm
 UIProcess/API/Cocoa/_WKInspectorWindow.mm
 UIProcess/API/Cocoa/_WKInternalDebugFeature.mm
 UIProcess/API/Cocoa/_WKLinkIconParameters.mm
diff --git a/Source/WebKit/UIProcess/API/APIInspectorExtension.h b/Source/WebKit/UIProcess/API/APIInspectorExtension.h
new file mode 100644 (file)
index 0000000..7e0f18a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#include "APIObject.h"
+#include <wtf/Forward.h>
+
+namespace API {
+
+class InspectorExtension final : public API::ObjectImpl<Object::Type::InspectorExtension> {
+public:
+    static Ref<InspectorExtension> create(const WTF::String& identifier)
+    {
+        return adoptRef(*new InspectorExtension(identifier));
+    }
+
+    explicit InspectorExtension(const WTF::String& identifier)
+        : m_identifier(identifier)
+    {
+    }
+
+    const WTF::String& identifier() const { return m_identifier; }
+
+private:
+    WTF::String m_identifier;
+};
+
+} // namespace API
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
index 1899e81..86b1cf8 100644 (file)
 
 #import <Foundation/Foundation.h>
 #import <WebKit/WKFoundation.h>
+#import <WebKit/_WKInspectorExtensionHost.h>
+
+NS_ASSUME_NONNULL_BEGIN
 
 @class WKWebView;
 @class _WKFrameHandle;
+@class _WKInspectorExtension;
 @protocol _WKInspectorDelegate;
 
-NS_ASSUME_NONNULL_BEGIN
-
-@protocol _WKInspectorExtensionHost
-- (void)close;
-@end
-
 WK_CLASS_AVAILABLE(macos(10.14.4), ios(12.2))
 @interface _WKInspector : NSObject <_WKInspectorExtensionHost>
 
@@ -52,6 +50,7 @@ WK_CLASS_AVAILABLE(macos(10.14.4), ios(12.2))
 
 - (void)connect;
 - (void)show;
+- (void)close;
 - (void)hide;
 - (void)showConsole;
 - (void)showResources;
index 673411f..6c00b96 100644 (file)
@@ -27,6 +27,7 @@
 #import "_WKInspectorInternal.h"
 
 #import "InspectorDelegate.h"
+#import "WKError.h"
 #import "WKWebViewInternal.h"
 #import "WebPageProxy.h"
 #import "WebProcessProxy.h"
 #import <wtf/RetainPtr.h>
 #import <wtf/text/WTFString.h>
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+#import "APIInspectorExtension.h"
+#import "WebInspectorUIExtensionControllerProxy.h"
+#import "_WKInspectorExtensionInternal.h"
+#import <wtf/BlockPtr.h>
+#endif
+
 @implementation _WKInspector
 
 // MARK: _WKInspector methods
     return *_inspector;
 }
 
+// MARK: _WKInspectorExtensionHost methods
+
+- (void)registerExtensionWithID:(NSString *)extensionID displayName:(NSString *)displayName completionHandler:(void(^)(NSError *, _WKInspectorExtension *))completionHandler
+{
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    _inspector->extensionController().registerExtension(extensionID, displayName, [protectedExtensionID = retainPtr(extensionID), protectedSelf = retainPtr(self), capturedBlock = makeBlockPtr(completionHandler)] (Expected<bool, WebKit::InspectorExtensionError> result) mutable {
+        if (!result) {
+            capturedBlock([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:@{ NSLocalizedFailureReasonErrorKey: inspectorExtensionErrorToString(result.error())}], nil);
+            return;
+        }
+
+        capturedBlock(nil, [[wrapper(API::InspectorExtension::create(protectedExtensionID.get())) retain] autorelease]);
+    });
+#else
+    completionHandler([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil], nil);
+#endif
+}
+
+- (void)unregisterExtension:(_WKInspectorExtension *)extension completionHandler:(void(^)(NSError *))completionHandler
+{
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    _inspector->extensionController().unregisterExtension(extension.extensionID, [protectedSelf = retainPtr(self), capturedBlock = makeBlockPtr(completionHandler)] (Expected<bool, WebKit::InspectorExtensionError> result) mutable {
+        if (!result) {
+            capturedBlock([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:@{ NSLocalizedFailureReasonErrorKey: inspectorExtensionErrorToString(result.error())}]);
+            return;
+        }
+
+        capturedBlock(nil);
+    });
+#else
+    completionHandler([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil]);
+#endif
+}
+
 @end
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.h b/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.h
new file mode 100644 (file)
index 0000000..6c5a601
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WebKit/WKFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+WK_CLASS_AVAILABLE(macos(WK_MAC_TBA))
+@interface _WKInspectorExtension : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@property (readonly, nonatomic) NSString *extensionID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm
new file mode 100644 (file)
index 0000000..3f7de94
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "_WKInspectorExtensionInternal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation _WKInspectorExtension
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+- (instancetype)initWithIdentifier:(NSString *)extensionID
+{
+    if (!(self = [super init]))
+        return nil;
+
+    API::Object::constructInWrapper<API::InspectorExtension>(self, extensionID);
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    _extension->API::InspectorExtension::~InspectorExtension();
+
+    [super dealloc];
+}
+
+
+- (API::Object&)_apiObject
+{
+    return *_extension;
+}
+
+// MARK: Properties.
+
+- (NSString *)extensionID
+{
+    return _extension->identifier();
+}
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionHost.h b/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionHost.h
new file mode 100644 (file)
index 0000000..987d963
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WebKit/WKFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class _WKInspectorExtension;
+
+@protocol _WKInspectorExtensionHost
+@optional
+
+/**
+ * @abstract Registers a Web Extension with the associated Web Inspector.
+ * @param extensionID A unique identifier for the extension.
+ * @param displayName A localized display name for the extension.
+ * @param completionHandler The completion handler to be called when registration succeeds or fails.
+ *
+ * Web Extensions in Web Inspector are active as soon as they are registered.
+ */
+- (void)registerExtensionWithID:(NSString *)extensionID displayName:(NSString *)displayName completionHandler:(void(^)(NSError * _Nullable, _WKInspectorExtension * _Nullable))completionHandler;
+
+/**
+ * @abstract Unregisters a Web Extension with the associated Web Inspector.
+ * @param extensionID A unique identifier for the extension.
+ * @param completionHandler The completion handler to be called when unregistering succeeds or fails.
+ *
+ * Unregistering an extension will automatically close any associated sidebars/tabs.
+ */
+- (void)unregisterExtension:(_WKInspectorExtension *)extension completionHandler:(void(^)(NSError * _Nullable))completionHandler;
+
+/**
+ * @abstract Closes the associated Web Inspector instance. This will cause all
+ * registered _WKInspectorExtensions to be unregistered and invalidated.
+ */
+- (void)close;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionInternal.h b/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionInternal.h
new file mode 100644 (file)
index 0000000..90c45d5
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "_WKInspectorExtension.h"
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#import "APIInspectorExtension.h"
+#import "WKObject.h"
+
+namespace WebKit {
+
+template<> struct WrapperTraits<API::InspectorExtension> {
+    using WrapperClass = _WKInspectorExtension;
+};
+
+} // namespace WebKit
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface _WKInspectorExtension () <WKObject> {
+@package
+    API::ObjectStorage<API::InspectorExtension> _extension;
+}
+
+- (instancetype)initWithIdentifier:(NSString *)extensionIdentifier;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
index b9a8b20..ba3fc13 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #import <WebKit/WKFoundation.h>
+#import <WebKit/_WKInspectorExtensionHost.h>
 
 #if !TARGET_OS_IPHONE
 
@@ -44,7 +45,7 @@ typedef NS_ENUM(NSInteger, WKRemoteWebInspectorDebuggableType) {
 } WK_API_AVAILABLE(macos(10.12.3), ios(10.3));
 
 WK_CLASS_AVAILABLE(macos(10.12.3), ios(10.3))
-@interface _WKRemoteWebInspectorViewController : NSObject
+@interface _WKRemoteWebInspectorViewController : NSObject <_WKInspectorExtensionHost>
 
 @property (nonatomic, assign) id <_WKRemoteWebInspectorViewControllerDelegate> delegate;
 
index 4e40b8b..91bd58f 100644 (file)
 #import "_WKInspectorConfigurationInternal.h"
 #import "_WKInspectorDebuggableInfoInternal.h"
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+#import "APIInspectorExtension.h"
+#import "WKError.h"
+#import "WebInspectorUIExtensionControllerProxy.h"
+#import "_WKInspectorExtensionInternal.h"
+#import <wtf/BlockPtr.h>
+#endif
+
 NS_ASSUME_NONNULL_BEGIN
 
 @interface _WKRemoteWebInspectorViewController ()
@@ -182,6 +190,40 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     m_remoteInspectorProxy->setDiagnosticLoggingAvailable(!!delegate);
 }
 
+// MARK: _WKInspectorExtensionHost methods
+
+- (void)registerExtensionWithID:(NSString *)extensionID displayName:(NSString *)displayName completionHandler:(void(^)(NSError *, _WKInspectorExtension *))completionHandler
+{
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_remoteInspectorProxy->extensionController().registerExtension(extensionID, displayName, [protectedExtensionID = retainPtr(extensionID), protectedSelf = retainPtr(self), capturedBlock = makeBlockPtr(completionHandler)] (Expected<bool, WebKit::InspectorExtensionError> result) mutable {
+        if (!result) {
+            capturedBlock([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:@{ NSLocalizedFailureReasonErrorKey: inspectorExtensionErrorToString(result.error())}], nil);
+            return;
+        }
+
+        capturedBlock(nil, [[wrapper(API::InspectorExtension::create(protectedExtensionID.get())) retain] autorelease]);
+    });
+#else
+    completionHandler([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil], nil);
+#endif
+}
+
+- (void)unregisterExtension:(_WKInspectorExtension *)extension completionHandler:(void(^)(NSError *))completionHandler
+{
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_remoteInspectorProxy->extensionController().unregisterExtension(extension.extensionID, [protectedSelf = retainPtr(self), capturedBlock = makeBlockPtr(completionHandler)] (Expected<bool, WebKit::InspectorExtensionError> result) mutable {
+        if (!result) {
+            capturedBlock([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:@{ NSLocalizedFailureReasonErrorKey: inspectorExtensionErrorToString(result.error())}]);
+            return;
+        }
+
+        capturedBlock(nil);
+    });
+#else
+    completionHandler([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil]);
+#endif
+}
+
 @end
 
 NS_ASSUME_NONNULL_END
index b047393..f5a022e 100644 (file)
 #include <WebCore/CertificateInfo.h>
 #include <WebCore/NotImplemented.h>
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+#include "WebInspectorUIExtensionControllerProxy.h"
+#endif
+
 namespace WebKit {
 using namespace WebCore;
 
@@ -95,6 +99,13 @@ void RemoteWebInspectorProxy::sendMessageToFrontend(const String& message)
     m_inspectorPage->send(Messages::RemoteWebInspectorUI::SendMessageToFrontend(message));
 }
 
+void RemoteWebInspectorProxy::frontendLoaded()
+{
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController->inspectorFrontendLoaded();
+#endif
+}
+
 void RemoteWebInspectorProxy::frontendDidClose()
 {
     Ref<RemoteWebInspectorProxy> protect(*this);
@@ -175,6 +186,10 @@ void RemoteWebInspectorProxy::createFrontendPageAndWindow()
 
     m_inspectorPage->process().addMessageReceiver(Messages::RemoteWebInspectorProxy::messageReceiverName(), m_inspectorPage->webPageID(), *this);
     m_inspectorPage->process().assumeReadAccessToBaseURL(*m_inspectorPage, WebInspectorProxy::inspectorBaseURL());
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = makeUnique<WebInspectorUIExtensionControllerProxy>(*m_inspectorPage);
+#endif
 }
 
 void RemoteWebInspectorProxy::closeFrontendPageAndWindow()
index c03a2ca..0f1c098 100644 (file)
@@ -56,6 +56,9 @@ namespace WebKit {
 class RemoteWebInspectorProxy;
 class WebPageProxy;
 class WebView;
+#if ENABLE(INSPECTOR_EXTENSIONS)
+class WebInspectorUIExtensionControllerProxy;
+#endif
 
 class RemoteWebInspectorProxyClient {
 public:
@@ -88,6 +91,10 @@ public:
 
     void sendMessageToFrontend(const String& message);
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    WebInspectorUIExtensionControllerProxy& extensionController() const { return *m_extensionController; }
+#endif
+    
 #if PLATFORM(MAC)
     NSWindow *window() const { return m_window.get(); }
     WKWebView *webView() const;
@@ -117,6 +124,7 @@ private:
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
 
     // RemoteWebInspectorProxy messages.
+    void frontendLoaded();
     void frontendDidClose();
     void reopen();
     void resetState();
@@ -149,6 +157,10 @@ private:
     RemoteWebInspectorProxyClient* m_client { nullptr };
     WebPageProxy* m_inspectorPage { nullptr };
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    std::unique_ptr<WebInspectorUIExtensionControllerProxy> m_extensionController;
+#endif
+    
     Ref<API::DebuggableInfo> m_debuggableInfo;
     String m_backendCommandsURL;
 
index 3beffd5..674bec3 100644 (file)
@@ -21,6 +21,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 messages -> RemoteWebInspectorProxy {
+    FrontendLoaded()
     FrontendDidClose()
     Reopen()
     ResetState()
index f0f7b2d..080b158 100644 (file)
@@ -37,6 +37,7 @@
 #include "WebInspectorInterruptDispatcherMessages.h"
 #include "WebInspectorMessages.h"
 #include "WebInspectorProxyMessages.h"
+#include "WebInspectorUIExtensionControllerProxy.h"
 #include "WebInspectorUIMessages.h"
 #include "WebPageGroup.h"
 #include "WebPageInspectorController.h"
@@ -421,6 +422,10 @@ void WebInspectorProxy::createFrontendPage()
 
     m_inspectorPage->process().addMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->identifier(), *this);
     m_inspectorPage->process().assumeReadAccessToBaseURL(*m_inspectorPage, WebInspectorProxy::inspectorBaseURL());
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = makeUnique<WebInspectorUIExtensionControllerProxy>(*m_inspectorPage);
+#endif
 }
 
 void WebInspectorProxy::openLocalInspectorFrontend(bool canAttach, bool underTest)
@@ -546,6 +551,10 @@ void WebInspectorProxy::closeFrontendPageAndWindow()
     if (m_isAttached)
         platformDetach();
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = nullptr;
+#endif
+    
     // Null out m_inspectorPage after platformDetach(), so the views can be cleaned up correctly.
     m_inspectorPage = nullptr;
 
@@ -571,6 +580,10 @@ void WebInspectorProxy::frontendLoaded()
 
     if (auto* automationSession = m_inspectedPage->process().processPool().automationSession())
         automationSession->inspectorFrontendLoaded(*m_inspectedPage);
+    
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController->inspectorFrontendLoaded();
+#endif
 }
 
 void WebInspectorProxy::bringToFront()
index 14d477e..f5541bf 100644 (file)
@@ -37,6 +37,7 @@
 #include <WebCore/InspectorFrontendClient.h>
 #include <wtf/Forward.h>
 #include <wtf/RefPtr.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 #if PLATFORM(MAC)
@@ -69,6 +70,9 @@ class WebFrameProxy;
 class WebInspectorProxyClient;
 class WebPageProxy;
 class WebPreferences;
+#if ENABLE(INSPECTOR_EXTENSIONS)
+class WebInspectorUIExtensionControllerProxy;
+#endif
 
 enum class AttachmentSide {
     Bottom,
@@ -80,6 +84,7 @@ class WebInspectorProxy
     : public API::ObjectImpl<API::Object::Type::Inspector>
     , public IPC::MessageReceiver
     , public Inspector::FrontendChannel
+    , public CanMakeWeakPtr<WebInspectorProxy>
 #if PLATFORM(WIN)
     , public WebCore::WindowMessageListener
 #endif
@@ -102,6 +107,10 @@ public:
     WebPageProxy* inspectedPage() const { return m_inspectedPage; }
     WebPageProxy* inspectorPage() const { return m_inspectorPage; }
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    WebInspectorUIExtensionControllerProxy& extensionController() const { return *m_extensionController; }
+#endif
+
     bool isConnected() const { return !!m_inspectorPage; }
     bool isVisible() const { return m_isVisible; }
     bool isFront();
@@ -286,6 +295,10 @@ private:
     WebPageProxy* m_inspectorPage { nullptr };
     std::unique_ptr<API::InspectorClient> m_inspectorClient;
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    std::unique_ptr<WebInspectorUIExtensionControllerProxy> m_extensionController;
+#endif
+    
     bool m_underTest { false };
     bool m_isVisible { false };
     bool m_isAttached { false };
diff --git a/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp b/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp
new file mode 100644 (file)
index 0000000..8b9abd7
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebInspectorUIExtensionControllerProxy.h"
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#include "WebInspectorUIExtensionControllerMessages.h"
+#include "WebPageProxy.h"
+#include "WebProcessProxy.h"
+
+namespace WebKit {
+
+WebInspectorUIExtensionControllerProxy::WebInspectorUIExtensionControllerProxy(WebPageProxy& inspectorPage)
+    : m_inspectorPage(makeWeakPtr(inspectorPage))
+{
+}
+
+WebInspectorUIExtensionControllerProxy::~WebInspectorUIExtensionControllerProxy()
+{
+    if (!m_inspectorPage)
+        return;
+
+    m_inspectorPage = nullptr;
+
+    auto callbacks = std::exchange(m_frontendLoadedCallbackQueue, { });
+    for (auto& callback : callbacks)
+        callback();
+}
+
+void WebInspectorUIExtensionControllerProxy::whenFrontendHasLoaded(Function<void()>&& callback)
+{
+    if (m_frontendLoaded && m_inspectorPage) {
+        callback();
+        return;
+    }
+
+    m_frontendLoadedCallbackQueue.append(WTFMove(callback));
+}
+
+void WebInspectorUIExtensionControllerProxy::inspectorFrontendLoaded()
+{
+    ASSERT(m_inspectorPage);
+
+    m_frontendLoaded = true;
+
+    auto callbacks = std::exchange(m_frontendLoadedCallbackQueue, { });
+    for (auto& callback : callbacks)
+        callback();
+}
+
+// API
+
+void WebInspectorUIExtensionControllerProxy::registerExtension(const InspectorExtensionID& extensionID, const String& displayName, WTF::CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
+{
+    whenFrontendHasLoaded([weakThis = makeWeakPtr(this), extensionID, displayName, completionHandler = WTFMove(completionHandler)] () mutable {
+        if (!weakThis || !weakThis->m_inspectorPage) {
+            completionHandler(makeUnexpected(InspectorExtensionError::InvalidRequest));
+            return;
+        }
+
+        weakThis->m_inspectorPage->sendWithAsyncReply(Messages::WebInspectorUIExtensionController::RegisterExtension { extensionID, displayName }, WTFMove(completionHandler));
+    });
+}
+
+void WebInspectorUIExtensionControllerProxy::unregisterExtension(const InspectorExtensionID& extensionID, WTF::CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
+{
+    whenFrontendHasLoaded([weakThis = makeWeakPtr(this), extensionID, completionHandler = WTFMove(completionHandler)] () mutable {
+        if (!weakThis || !weakThis->m_inspectorPage) {
+            completionHandler(makeUnexpected(InspectorExtensionError::InvalidRequest));
+            return;
+        }
+
+        weakThis->m_inspectorPage->sendWithAsyncReply(Messages::WebInspectorUIExtensionController::UnregisterExtension { extensionID }, WTFMove(completionHandler));
+    });
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
diff --git a/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h b/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h
new file mode 100644 (file)
index 0000000..203410a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#include "InspectorExtensionTypes.h"
+#include "MessageReceiver.h"
+#include <wtf/Expected.h>
+#include <wtf/Forward.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class WebInspectorUIExtensionControllerProxy final
+    : public IPC::MessageReceiver
+    , public CanMakeWeakPtr<WebInspectorUIExtensionControllerProxy> {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(WebInspectorUIExtensionControllerProxy);
+public:
+    explicit WebInspectorUIExtensionControllerProxy(WebPageProxy& inspectorPage);
+    virtual ~WebInspectorUIExtensionControllerProxy();
+
+    // API.
+    void registerExtension(const InspectorExtensionID&, const String& displayName, WTF::CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
+    void unregisterExtension(const InspectorExtensionID&, WTF::CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
+
+    // Notifications.
+    void inspectorFrontendLoaded();
+
+private:
+    void whenFrontendHasLoaded(Function<void()>&&);
+
+    WeakPtr<WebPageProxy> m_inspectorPage;
+
+    // Used to queue actions such as registering extensions that happen early on.
+    // There's no point sending these before the frontend is fully loaded.
+    Vector<Function<void()>> m_frontendLoadedCallbackQueue;
+
+    bool m_frontendLoaded { false };
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
index 75d7d8e..3860d96 100644 (file)
@@ -148,14 +148,14 @@ static Optional<Vector<Ref<AuthenticatorAssertionResponse>>> getExistingCredenti
         }
         auto& responseMap = decodedResponse->getMap();
 
-        auto it = responseMap.find(CBOR(kEntityIdMapKey));
+        auto it = responseMap.find(CBOR(fido::kEntityIdMapKey));
         if (it == responseMap.end() || !it->second.isByteString()) {
             ASSERT_NOT_REACHED();
             return WTF::nullopt;
         }
         auto& userHandle = it->second.getByteString();
 
-        it = responseMap.find(CBOR(kEntityNameMapKey));
+        it = responseMap.find(CBOR(fido::kEntityNameMapKey));
         if (it == responseMap.end() || !it->second.isString()) {
             ASSERT_NOT_REACHED();
             return WTF::nullopt;
@@ -299,8 +299,8 @@ void LocalAuthenticator::continueMakeCredentialAfterUserVerification(SecAccessCo
     const auto& secAttrLabel = creationOptions.rp.id;
 
     cbor::CBORValue::MapValue userEntityMap;
-    userEntityMap[cbor::CBORValue(kEntityIdMapKey)] = cbor::CBORValue(creationOptions.user.idVector);
-    userEntityMap[cbor::CBORValue(kEntityNameMapKey)] = cbor::CBORValue(creationOptions.user.name);
+    userEntityMap[cbor::CBORValue(fido::kEntityIdMapKey)] = cbor::CBORValue(creationOptions.user.idVector);
+    userEntityMap[cbor::CBORValue(fido::kEntityNameMapKey)] = cbor::CBORValue(creationOptions.user.name);
     auto userEntity = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(userEntityMap)));
     ASSERT(userEntity);
     auto secAttrApplicationTag = toNSData(*userEntity);
index 1d63c2b..8aca605 100644 (file)
                9955A6F61C7986E300EB6A93 /* AutomationProtocolObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9955A6F21C79866400EB6A93 /* AutomationProtocolObjects.cpp */; };
                9955A6F71C7986E500EB6A93 /* AutomationProtocolObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = 9955A6F31C79866400EB6A93 /* AutomationProtocolObjects.h */; };
                99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 99788AC91F421DCA00C08000 /* _WKAutomationSessionConfiguration.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               9979659E25310A4900B31AE3 /* WebInspectorUIExtensionControllerMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 9979659A25310A4800B31AE3 /* WebInspectorUIExtensionControllerMessages.h */; };
+               9979659F25310A4900B31AE3 /* WebInspectorUIExtensionControllerMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9979659B25310A4800B31AE3 /* WebInspectorUIExtensionControllerMessageReceiver.cpp */; };
+               997965A3253128C700B31AE3 /* _WKInspectorExtensionHost.h in Headers */ = {isa = PBXBuildFile; fileRef = 997965A2253128C700B31AE3 /* _WKInspectorExtensionHost.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9979CA58237F49F10039EC05 /* _WKInspectorPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9979CA57237F49F00039EC05 /* _WKInspectorPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                99996A9F25004BCC004F7559 /* _WKInspectorPrivateForTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = 99996A9D25004BCB004F7559 /* _WKInspectorPrivateForTesting.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               99B16757252BB7E10073140E /* _WKInspectorExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 99B16754252BB7E00073140E /* _WKInspectorExtension.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               99B16758252BB7E10073140E /* _WKInspectorExtensionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 99B16755252BB7E10073140E /* _WKInspectorExtensionInternal.h */; };
+               99B1675B252BBADD0073140E /* WebInspectorUIExtensionControllerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 99B1675A252BBADD0073140E /* WebInspectorUIExtensionControllerProxy.h */; };
+               99B16764252BBE620073140E /* WebInspectorUIExtensionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 99B16761252BBE610073140E /* WebInspectorUIExtensionController.h */; };
                99C3AE2D1DADA6AD00AF5C16 /* WebAutomationSessionMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C3AE2C1DADA6A700AF5C16 /* WebAutomationSessionMacros.h */; };
                99C81D5A1C20E7E2005C4C82 /* AutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D551C20DFBE005C4C82 /* AutomationClient.h */; };
                99C81D5D1C21F38B005C4C82 /* APIAutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D5B1C20E817005C4C82 /* APIAutomationClient.h */; };
                9955A6F31C79866400EB6A93 /* AutomationProtocolObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AutomationProtocolObjects.h; path = DerivedSources/WebKit2/AutomationProtocolObjects.h; sourceTree = BUILT_PRODUCTS_DIR; };
                99788AC91F421DCA00C08000 /* _WKAutomationSessionConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKAutomationSessionConfiguration.h; sourceTree = "<group>"; };
                99788ACA1F421DCA00C08000 /* _WKAutomationSessionConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKAutomationSessionConfiguration.mm; sourceTree = "<group>"; };
+               9979659A25310A4800B31AE3 /* WebInspectorUIExtensionControllerMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebInspectorUIExtensionControllerMessages.h; path = DerivedSources/WebKit2/WebInspectorUIExtensionControllerMessages.h; sourceTree = BUILT_PRODUCTS_DIR; };
+               9979659B25310A4800B31AE3 /* WebInspectorUIExtensionControllerMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebInspectorUIExtensionControllerMessageReceiver.cpp; path = DerivedSources/WebKit2/WebInspectorUIExtensionControllerMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
+               997965A2253128C700B31AE3 /* _WKInspectorExtensionHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorExtensionHost.h; sourceTree = "<group>"; };
                9979CA57237F49F00039EC05 /* _WKInspectorPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorPrivate.h; sourceTree = "<group>"; };
                99996A9D25004BCB004F7559 /* _WKInspectorPrivateForTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorPrivateForTesting.h; sourceTree = "<group>"; };
                99996A9E25004BCB004F7559 /* _WKInspectorTesting.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKInspectorTesting.mm; sourceTree = "<group>"; };
+               999B7ED82550E4A800F450A4 /* InspectorExtensionTypes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorExtensionTypes.cpp; sourceTree = "<group>"; };
+               99B16754252BB7E00073140E /* _WKInspectorExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorExtension.h; sourceTree = "<group>"; };
+               99B16755252BB7E10073140E /* _WKInspectorExtensionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorExtensionInternal.h; sourceTree = "<group>"; };
+               99B16756252BB7E10073140E /* _WKInspectorExtension.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKInspectorExtension.mm; sourceTree = "<group>"; };
+               99B1675A252BBADD0073140E /* WebInspectorUIExtensionControllerProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebInspectorUIExtensionControllerProxy.h; sourceTree = "<group>"; };
+               99B1675D252BBE0A0073140E /* WebInspectorUIExtensionControllerProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebInspectorUIExtensionControllerProxy.cpp; sourceTree = "<group>"; };
+               99B16760252BBE610073140E /* WebInspectorUIExtensionController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebInspectorUIExtensionController.cpp; sourceTree = "<group>"; };
+               99B16761252BBE610073140E /* WebInspectorUIExtensionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebInspectorUIExtensionController.h; sourceTree = "<group>"; };
+               99B16762252BBE610073140E /* WebInspectorUIExtensionController.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebInspectorUIExtensionController.messages.in; sourceTree = "<group>"; };
+               99BE3B1225422F4100C6551C /* APIInspectorExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIInspectorExtension.h; sourceTree = "<group>"; };
+               99BE3B1625433B9400C6551C /* InspectorExtensionTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorExtensionTypes.h; sourceTree = "<group>"; };
                99C3AE231DAD8E3400AF5C16 /* WebAutomationSessionMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebAutomationSessionMac.mm; sourceTree = "<group>"; };
                99C3AE261DAD948500AF5C16 /* WebAutomationSessionCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebAutomationSessionCocoa.mm; sourceTree = "<group>"; };
                99C3AE2C1DADA6A700AF5C16 /* WebAutomationSessionMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAutomationSessionMacros.h; sourceTree = "<group>"; };
                                5C121E8324101F7000486F9B /* FrameTreeNodeData.h */,
                                1AC75A1A1B3368270056745B /* HangDetectionDisabler.h */,
                                BCCF6B2312C93E7A008F9C35 /* ImageOptions.h */,
+                               999B7ED82550E4A800F450A4 /* InspectorExtensionTypes.cpp */,
+                               99BE3B1625433B9400C6551C /* InspectorExtensionTypes.h */,
                                1A92DC1212F8BAB90017AF65 /* LayerTreeContext.cpp */,
                                1A92DC1012F8BA460017AF65 /* LayerTreeContext.h */,
                                2D10875E1D2C573E00B85F82 /* LoadParameters.cpp */,
                                991F492E23A812C60054642B /* _WKInspectorDebuggableInfo.mm */,
                                99036AE123A949CE0000B06A /* _WKInspectorDebuggableInfoInternal.h */,
                                9197940B23DBC50300257892 /* _WKInspectorDelegate.h */,
+                               99B16754252BB7E00073140E /* _WKInspectorExtension.h */,
+                               99B16756252BB7E10073140E /* _WKInspectorExtension.mm */,
+                               997965A2253128C700B31AE3 /* _WKInspectorExtensionHost.h */,
+                               99B16755252BB7E10073140E /* _WKInspectorExtensionInternal.h */,
                                5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */,
                                9979CA57237F49F00039EC05 /* _WKInspectorPrivate.h */,
                                99996A9D25004BCB004F7559 /* _WKInspectorPrivateForTesting.h */,
                                1C8E28331275D73800BC7BD0 /* WebInspectorProxy.cpp */,
                                1C8E28321275D73800BC7BD0 /* WebInspectorProxy.h */,
                                1C77C1951288A872006A742F /* WebInspectorProxy.messages.in */,
+                               99B1675D252BBE0A0073140E /* WebInspectorUIExtensionControllerProxy.cpp */,
+                               99B1675A252BBADD0073140E /* WebInspectorUIExtensionControllerProxy.h */,
                                A55BA8271BA38E1E007CD33D /* WebInspectorUtilities.cpp */,
                                A55BA8281BA38E1E007CD33D /* WebInspectorUtilities.h */,
                                A5EC6AD22151BD6900677D17 /* WebPageDebuggable.cpp */,
                                1C891D6219B124FF00BA79DD /* WebInspectorUI.cpp */,
                                1C891D6319B124FF00BA79DD /* WebInspectorUI.h */,
                                1C891D6419B124FF00BA79DD /* WebInspectorUI.messages.in */,
+                               99B16760252BBE610073140E /* WebInspectorUIExtensionController.cpp */,
+                               99B16761252BBE610073140E /* WebInspectorUIExtensionController.h */,
+                               99B16762252BBE610073140E /* WebInspectorUIExtensionController.messages.in */,
                                A543E30A215C8A8400279CD9 /* WebPageInspectorTarget.cpp */,
                                A543E308215C8A8300279CD9 /* WebPageInspectorTarget.h */,
                                A543E309215C8A8300279CD9 /* WebPageInspectorTargetController.cpp */,
                                9197940923DBC4E000257892 /* APIInspectorClient.h */,
                                994C6048253F820200BDF060 /* APIInspectorConfiguration.cpp */,
                                994C6046253CACB800BDF060 /* APIInspectorConfiguration.h */,
+                               99BE3B1225422F4100C6551C /* APIInspectorExtension.h */,
                                31B362902141EABC007BFA53 /* APIInternalDebugFeature.cpp */,
                                31B3628E2141EA4D007BFA53 /* APIInternalDebugFeature.h */,
                                7CE4D2061A46775700C7F152 /* APILegacyContextHistoryClient.h */,
                                1C8E2A321277852400BC7BD0 /* WebInspectorMessages.h */,
                                1CA8B943127C882A00576C2B /* WebInspectorProxyMessageReceiver.cpp */,
                                1CA8B944127C882A00576C2B /* WebInspectorProxyMessages.h */,
+                               9979659B25310A4800B31AE3 /* WebInspectorUIExtensionControllerMessageReceiver.cpp */,
+                               9979659A25310A4800B31AE3 /* WebInspectorUIExtensionControllerMessages.h */,
                                1CBBE49E19B66C53006B7D81 /* WebInspectorUIMessageReceiver.cpp */,
                                1CBBE49F19B66C53006B7D81 /* WebInspectorUIMessages.h */,
                                51F060DD1654317500F3282F /* WebMDNSRegisterMessageReceiver.cpp */,
                                991F492F23A812C60054642B /* _WKInspectorDebuggableInfo.h in Headers */,
                                99036AE223A949CF0000B06A /* _WKInspectorDebuggableInfoInternal.h in Headers */,
                                9197940C23DBC50300257892 /* _WKInspectorDelegate.h in Headers */,
+                               99B16757252BB7E10073140E /* _WKInspectorExtension.h in Headers */,
+                               997965A3253128C700B31AE3 /* _WKInspectorExtensionHost.h in Headers */,
+                               99B16758252BB7E10073140E /* _WKInspectorExtensionInternal.h in Headers */,
                                5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */,
                                9979CA58237F49F10039EC05 /* _WKInspectorPrivate.h in Headers */,
                                99996A9F25004BCC004F7559 /* _WKInspectorPrivateForTesting.h in Headers */,
                                1C8E28341275D73800BC7BD0 /* WebInspectorProxy.h in Headers */,
                                1CA8B946127C882A00576C2B /* WebInspectorProxyMessages.h in Headers */,
                                1C891D6619B124FF00BA79DD /* WebInspectorUI.h in Headers */,
+                               99B16764252BBE620073140E /* WebInspectorUIExtensionController.h in Headers */,
+                               9979659E25310A4900B31AE3 /* WebInspectorUIExtensionControllerMessages.h in Headers */,
+                               99B1675B252BBADD0073140E /* WebInspectorUIExtensionControllerProxy.h in Headers */,
                                1CBBE4A119B66C53006B7D81 /* WebInspectorUIMessages.h in Headers */,
                                A55BA82B1BA38E61007CD33D /* WebInspectorUtilities.h in Headers */,
                                2DA944A01884E4F000ED86DB /* WebIOSEventFactory.h in Headers */,
                                FEDBDCD61E68D20000A59F8F /* WebInspectorInterruptDispatcherMessageReceiver.cpp in Sources */,
                                1C8E2A351277852400BC7BD0 /* WebInspectorMessageReceiver.cpp in Sources */,
                                1CA8B945127C882A00576C2B /* WebInspectorProxyMessageReceiver.cpp in Sources */,
+                               9979659F25310A4900B31AE3 /* WebInspectorUIExtensionControllerMessageReceiver.cpp in Sources */,
                                1CBBE4A019B66C53006B7D81 /* WebInspectorUIMessageReceiver.cpp in Sources */,
                                2D92A78A212B6AB100F493FD /* WebKeyboardEvent.cpp in Sources */,
                                1A6280F31919982A006AD9F9 /* WebKit.m in Sources */,
index 6771c6f..d1390bf 100644 (file)
 #include <WebCore/InspectorController.h>
 #include <WebCore/Settings.h>
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+#include "WebInspectorUIExtensionController.h"
+#endif
+
 #if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(WIN)
 #include <WebCore/NotImplemented.h>
 #endif
@@ -58,8 +62,14 @@ RemoteWebInspectorUI::RemoteWebInspectorUI(WebPage& page)
     WebInspectorUI::enableFrontendFeatures();
 }
 
+RemoteWebInspectorUI::~RemoteWebInspectorUI() = default;
+
 void RemoteWebInspectorUI::initialize(DebuggableInfoData&& debuggableInfo, const String& backendCommandsURL)
 {
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = makeUnique<WebInspectorUIExtensionController>(*this);
+#endif
+
     m_debuggableInfo = WTFMove(debuggableInfo);
     m_backendCommandsURL = backendCommandsURL;
 
@@ -109,6 +119,8 @@ void RemoteWebInspectorUI::frontendLoaded()
 
     m_frontendAPIDispatcher->dispatchCommandWithResultAsync("setIsVisible"_s, { JSON::Value::create(true) });
 
+    WebProcess::singleton().parentProcessConnection()->send(Messages::RemoteWebInspectorProxy::FrontendLoaded(), m_page.identifier());
+
     bringToFront();
 }
 
@@ -174,6 +186,10 @@ void RemoteWebInspectorUI::closeWindow()
 {
     m_page.corePage()->inspectorController().setInspectorFrontendClient(nullptr);
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = nullptr;
+#endif
+    
     WebProcess::singleton().parentProcessConnection()->send(Messages::RemoteWebInspectorProxy::FrontendDidClose(), m_page.identifier());
 }
 
@@ -258,6 +274,12 @@ void RemoteWebInspectorUI::setDiagnosticLoggingAvailable(bool available)
 }
 #endif
 
+WebCore::Page* RemoteWebInspectorUI::frontendPage()
+{
+    return m_page.corePage();
+}
+
+
 #if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(WIN)
 String RemoteWebInspectorUI::localizedStringsURL() const
 {
index 025ec90..b8da9a9 100644 (file)
@@ -39,11 +39,16 @@ class FloatRect;
 
 namespace WebKit {
 
+class WebInspectorUIExtensionController;
 class WebPage;
 
-class RemoteWebInspectorUI final : public RefCounted<RemoteWebInspectorUI>, public IPC::MessageReceiver, public WebCore::InspectorFrontendClient {
+class RemoteWebInspectorUI final
+    : public RefCounted<RemoteWebInspectorUI>
+    , public IPC::MessageReceiver
+    , public WebCore::InspectorFrontendClient {
 public:
     static Ref<RemoteWebInspectorUI> create(WebPage&);
+    ~RemoteWebInspectorUI();
 
     // Implemented in generated RemoteWebInspectorUIMessageReceiver.cpp
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
@@ -97,6 +102,7 @@ public:
     void showCertificate(const WebCore::CertificateInfo&) override;
     void sendMessageToBackend(const String&) override;
     WebCore::InspectorFrontendAPIDispatcher& frontendAPIDispatcher() override { return m_frontendAPIDispatcher; }
+    WebCore::Page* frontendPage() final;
 
 #if ENABLE(INSPECTOR_TELEMETRY)
     bool supportsDiagnosticLogging() override;
@@ -117,6 +123,10 @@ private:
     WebPage& m_page;
     Ref<WebCore::InspectorFrontendAPIDispatcher> m_frontendAPIDispatcher;
     RefPtr<WebCore::InspectorFrontendHost> m_frontendHost;
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    std::unique_ptr<WebInspectorUIExtensionController> m_extensionController;
+#endif
+
     DebuggableInfoData m_debuggableInfo;
     String m_backendCommandsURL;
 
index 82809ad..c2d8836 100644 (file)
 #include <WebCore/DOMWrapperWorld.h>
 #include <WebCore/FloatRect.h>
 #include <WebCore/InspectorController.h>
+#include <WebCore/InspectorFrontendHost.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/RuntimeEnabledFeatures.h>
 #include <WebCore/Settings.h>
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+#include "WebInspectorUIExtensionController.h"
+#endif
+
 namespace WebKit {
 using namespace WebCore;
 
@@ -65,6 +70,8 @@ WebInspectorUI::WebInspectorUI(WebPage& page)
     WebInspectorUI::enableFrontendFeatures();
 }
 
+WebInspectorUI::~WebInspectorUI() = default;
+
 void WebInspectorUI::establishConnection(WebPageProxyIdentifier inspectedPageIdentifier, const DebuggableInfoData& debuggableInfo, bool underTest, unsigned inspectionLevel)
 {
     m_inspectedPageIdentifier = inspectedPageIdentifier;
@@ -72,8 +79,11 @@ void WebInspectorUI::establishConnection(WebPageProxyIdentifier inspectedPageIde
     m_underTest = underTest;
     m_inspectionLevel = inspectionLevel;
 
-    m_frontendAPIDispatcher->reset();
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = makeUnique<WebInspectorUIExtensionController>(*this);
+#endif
 
+    m_frontendAPIDispatcher->reset();
     m_frontendController = &m_page.corePage()->inspectorController();
     m_frontendController->setInspectorFrontendClient(this);
 
@@ -165,6 +175,10 @@ void WebInspectorUI::closeWindow()
 
     m_inspectedPageIdentifier = { };
     m_underTest = false;
+    
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    m_extensionController = nullptr;
+#endif
 }
 
 void WebInspectorUI::reopen()
@@ -412,6 +426,12 @@ String WebInspectorUI::targetProductVersion() const
     return m_debuggableInfo.targetProductVersion;
 }
 
+WebCore::Page* WebInspectorUI::frontendPage()
+{
+    return m_page.corePage();
+}
+
+
 #if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(WIN)
 bool WebInspectorUI::canSave()
 {
index a6ee713..24c1ab4 100644 (file)
 #include <WebCore/InspectorDebuggableType.h>
 #include <WebCore/InspectorFrontendAPIDispatcher.h>
 #include <WebCore/InspectorFrontendClient.h>
-#include <WebCore/InspectorFrontendHost.h>
 
 namespace WebCore {
 class InspectorController;
+class InspectorFrontendHost;
 class CertificateInfo;
 class FloatRect;
 }
@@ -42,10 +42,17 @@ class FloatRect;
 namespace WebKit {
 
 class WebPage;
+#if ENABLE(INSPECTOR_EXTENSIONS)
+class WebInspectorUIExtensionController;
+#endif
 
-class WebInspectorUI : public RefCounted<WebInspectorUI>, private IPC::Connection::Client, public WebCore::InspectorFrontendClient {
+class WebInspectorUI final
+    : public RefCounted<WebInspectorUI>
+    , private IPC::Connection::Client
+    , public WebCore::InspectorFrontendClient {
 public:
     static Ref<WebInspectorUI> create(WebPage&);
+    virtual ~WebInspectorUI();
 
     static void enableFrontendFeatures();
 
@@ -143,7 +150,8 @@ public:
 
     void sendMessageToBackend(const String&) override;
     WebCore::InspectorFrontendAPIDispatcher& frontendAPIDispatcher() final { return m_frontendAPIDispatcher; }
-
+    WebCore::Page* frontendPage() final;
+        
     void pagePaused() override;
     void pageUnpaused() override;
 
@@ -160,6 +168,10 @@ private:
     // corePage(), since we may need it after the frontend's page has started destruction.
     WebCore::InspectorController* m_frontendController { nullptr };
 
+#if ENABLE(INSPECTOR_EXTENSIONS)
+    std::unique_ptr<WebInspectorUIExtensionController> m_extensionController;
+#endif
+
     WebPageProxyIdentifier m_inspectedPageIdentifier;
     bool m_underTest { false };
     DebuggableInfoData m_debuggableInfo;
diff --git a/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp b/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp
new file mode 100644 (file)
index 0000000..6a22372
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebInspectorUIExtensionController.h"
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#include "WebInspectorUI.h"
+#include "WebInspectorUIExtensionControllerMessages.h"
+#include "WebInspectorUIExtensionControllerMessagesReplies.h"
+#include "WebPage.h"
+#include "WebProcess.h"
+#include <WebCore/InspectorFrontendAPIDispatcher.h>
+
+namespace WebKit {
+
+WebInspectorUIExtensionController::WebInspectorUIExtensionController(WebCore::InspectorFrontendClient& inspectorFrontend)
+    : m_frontendClient(makeWeakPtr(inspectorFrontend))
+{
+    Page* page = inspectorFrontend.frontendPage();
+    ASSERT(page);
+
+    WebProcess::singleton().addMessageReceiver(Messages::WebInspectorUIExtensionController::messageReceiverName(), WebPage::fromCorePage(*page).identifier(), *this);
+}
+
+WebInspectorUIExtensionController::~WebInspectorUIExtensionController()
+{
+    WebProcess::singleton().removeMessageReceiver(*this);
+}
+
+Optional<InspectorExtensionError> WebInspectorUIExtensionController::parseInspectorExtensionErrorFromResult(JSC::JSValue result)
+{
+    ASSERT(m_frontendClient);
+    auto globalObject = m_frontendClient->frontendAPIDispatcher().frontendGlobalObject();
+    if (!globalObject)
+        return InspectorExtensionError::ContextDestroyed;
+
+    // If the evaluation result is a string, the frontend returned an error string.
+    // Anything else (falsy values, objects, arrays, DOM, etc.) is interpreted as success.
+    if (result.isString()) {
+        auto resultString = result.toWTFString(globalObject);
+        if (resultString == "ContextDestroyed"_s)
+            return InspectorExtensionError::ContextDestroyed;
+        if (resultString == "InternalError"_s)
+            return InspectorExtensionError::InternalError;
+        if (resultString == "InvalidRequest"_s)
+            return InspectorExtensionError::InvalidRequest;
+        if (resultString == "RegistrationFailed"_s)
+            return InspectorExtensionError::RegistrationFailed;
+
+        ASSERT_NOT_REACHED();
+        return InspectorExtensionError::InternalError;
+    }
+
+    return WTF::nullopt;
+}
+
+// WebInspectorUIExtensionController IPC messages.
+
+void WebInspectorUIExtensionController::registerExtension(const String& extensionID, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
+{
+    if (!m_frontendClient) {
+        completionHandler(makeUnexpected(InspectorExtensionError::InvalidRequest));
+        return;
+    }
+
+    Vector<Ref<JSON::Value>> arguments {
+        JSON::Value::create(extensionID),
+        JSON::Value::create(displayName),
+    };
+    m_frontendClient->frontendAPIDispatcher().dispatchCommandWithResultAsync("registerExtension"_s, WTFMove(arguments), [weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)](InspectorFrontendAPIDispatcher::EvaluationResult&& result) mutable {
+        if (!weakThis || !result) {
+            completionHandler(makeUnexpected(InspectorExtensionError::ContextDestroyed));
+            return;
+        }
+
+        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromResult(result.value())) {
+            completionHandler(makeUnexpected(parsedError.value()));
+            return;
+        }
+
+        completionHandler(true);
+    });
+}
+
+void WebInspectorUIExtensionController::unregisterExtension(const String& extensionID, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
+{
+    if (!m_frontendClient) {
+        completionHandler(makeUnexpected(InspectorExtensionError::InvalidRequest));
+        return;
+    }
+
+    Vector<Ref<JSON::Value>> arguments { JSON::Value::create(extensionID) };
+    m_frontendClient->frontendAPIDispatcher().dispatchCommandWithResultAsync("unregisterExtension"_s, WTFMove(arguments), [weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)](InspectorFrontendAPIDispatcher::EvaluationResult&& result) mutable {
+        if (!weakThis || !result) {
+            completionHandler(makeUnexpected(InspectorExtensionError::ContextDestroyed));
+            return;
+        }
+
+        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromResult(result.value())) {
+            completionHandler(makeUnexpected(parsedError.value()));
+            return;
+        }
+
+        completionHandler(true);
+    });
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
diff --git a/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h b/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h
new file mode 100644 (file)
index 0000000..f5b40ab
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#include "Connection.h"
+#include "InspectorExtensionTypes.h"
+#include "MessageReceiver.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/URL.h>
+#include <wtf/WeakPtr.h>
+
+namespace JSC {
+class JSValue;
+}
+
+namespace WebCore {
+class InspectorFrontendClient;
+}
+
+namespace WebKit {
+
+class WebInspectorUI;
+
+class WebInspectorUIExtensionController
+    : public IPC::MessageReceiver
+    , public CanMakeWeakPtr<WebInspectorUIExtensionController> {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(WebInspectorUIExtensionController);
+public:
+    explicit WebInspectorUIExtensionController(WebCore::InspectorFrontendClient&);
+    ~WebInspectorUIExtensionController();
+
+    // Implemented in generated WebInspectorUIExtensionControllerMessageReceiver.cpp
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
+
+    // WebInspectorUIExtensionController IPC messages.
+    void registerExtension(const String& extensionID, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
+    void unregisterExtension(const String& extensionID, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
+
+private:
+    Optional<InspectorExtensionError> parseInspectorExtensionErrorFromResult(JSC::JSValue result);
+
+    WeakPtr<WebCore::InspectorFrontendClient> m_frontendClient;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
diff --git a/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in b/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in
new file mode 100644 (file)
index 0000000..2c78ed7
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (C) 2020 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+messages -> WebInspectorUIExtensionController NotRefCounted {
+    RegisterExtension(String extensionID, String displayName) -> (Expected<bool, WebKit::InspectorExtensionError> result) Async
+    UnregisterExtension(String extensionID) -> (Expected<bool, WebKit::InspectorExtensionError> result) Async
+}
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
index 101e62f..4f15fad 100644 (file)
@@ -1,3 +1,19 @@
+2020-11-05  Brian Burg  <bburg@apple.com>
+
+        [Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
+        https://bugs.webkit.org/show_bug.cgi?id=217783
+        <rdar://problem/69968787>
+
+        Reviewed by Devin Rousso.
+
+        Add API tests to exercise new methods of the _WKInspectorExtensionHost protocol.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: New test file.
+        * TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionHost.mm: Added.
+        (resetGlobalState):
+        (-[UIDelegateForTestingInspectorExtensionHost _webView:didAttachLocalInspector:]):
+        (TEST):
+
 2020-11-05  Aakash Jain  <aakash_jain@apple.com>
 
         [build.webkit.org] Rename BUILD_WEBKIT_URL to CURRENT_HOSTNAME
index 26e4b79..b11fdc2 100644 (file)
                9984FACC1CFFAF60008D198C /* WKWebViewTextInput.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9984FACA1CFFAEEE008D198C /* WKWebViewTextInput.mm */; };
                9984FACE1CFFB090008D198C /* editable-body.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9984FACD1CFFB038008D198C /* editable-body.html */; };
                9999108B1F393C96008AD455 /* Copying.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9999108A1F393C8B008AD455 /* Copying.mm */; };
+               999B7EE32551C63B00F450A4 /* WKInspectorExtensionHost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */; };
                99B4F9C624EDED9700022B82 /* WKInspectorDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */; };
                9B02E0D6235FA47D004044B2 /* TextManipulation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B02E0D5235FA47D004044B2 /* TextManipulation.mm */; };
                9B0786A51C5885C300D159E3 /* InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B0786A41C5885C300D159E3 /* InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp */; };
                9984FACA1CFFAEEE008D198C /* WKWebViewTextInput.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewTextInput.mm; sourceTree = "<group>"; };
                9984FACD1CFFB038008D198C /* editable-body.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "editable-body.html"; sourceTree = "<group>"; };
                9999108A1F393C8B008AD455 /* Copying.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Copying.mm; sourceTree = "<group>"; };
+               999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtensionHost.mm; sourceTree = "<group>"; };
                99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorDelegate.mm; sourceTree = "<group>"; };
                9B02E0D5235FA47D004044B2 /* TextManipulation.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TextManipulation.mm; sourceTree = "<group>"; };
                9B0786A21C58830F00D159E3 /* InjectedBundleMakeAllShadowRootsOpen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleMakeAllShadowRootsOpen.cpp; sourceTree = "<group>"; };
                                370CE2291F57343400E7410B /* WKContentViewTargetForAction.mm */,
                                51D124971E763AF8002B2820 /* WKHTTPCookieStore.mm */,
                                99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */,
+                               999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */,
                                A5A729F01F622A9A00DE5A28 /* WKNavigationResponse.mm */,
                                DF4B273821A47727009BD1CA /* WKNSDictionaryEmptyDictionaryCrash.mm */,
                                375E0E151D66674400EFEC2C /* WKNSNumber.mm */,
                                51D124981E763B02002B2820 /* WKHTTPCookieStore.mm in Sources */,
                                7CCE7F1D1A411AE600447C4C /* WKImageCreateCGImageCrash.cpp in Sources */,
                                99B4F9C624EDED9700022B82 /* WKInspectorDelegate.mm in Sources */,
+                               999B7EE32551C63B00F450A4 /* WKInspectorExtensionHost.mm in Sources */,
                                A5A729F11F622AA700DE5A28 /* WKNavigationResponse.mm in Sources */,
                                DF4B273921A47728009BD1CA /* WKNSDictionaryEmptyDictionaryCrash.mm in Sources */,
                                375E0E171D66674400EFEC2C /* WKNSNumber.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionHost.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionHost.mm
new file mode 100644 (file)
index 0000000..5edacd7
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#import "Test.h"
+#import "Utilities.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKInspector.h>
+#import <WebKit/_WKInspectorPrivateForTesting.h>
+#import <wtf/RetainPtr.h>
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+static bool didAttachLocalInspectorCalled = false;
+static bool pendingCallbackWasCalled = false;
+
+static void resetGlobalState()
+{
+    didAttachLocalInspectorCalled = false;
+    pendingCallbackWasCalled = false;
+}
+
+@interface UIDelegateForTestingInspectorExtensionHost : NSObject <WKUIDelegate>
+@end
+
+@implementation UIDelegateForTestingInspectorExtensionHost
+
+- (void)_webView:(WKWebView *)webView didAttachLocalInspector:(_WKInspector *)inspector
+{
+    EXPECT_EQ(webView._inspector, inspector);
+    didAttachLocalInspectorCalled = true;
+}
+
+@end
+
+TEST(WKInspectorExtensionHost, RegisterExtension)
+{
+    resetGlobalState();
+
+    auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]);
+    webViewConfiguration.get().preferences._developerExtrasEnabled = YES;
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto uiDelegate = adoptNS([UIDelegateForTestingInspectorExtensionHost new]);
+
+    [webView setUIDelegate:uiDelegate.get()];
+    [webView loadHTMLString:@"<head><title>Test page to be inspected</title></head><body><p>Filler content</p></body>" baseURL:[NSURL URLWithString:@"http://example.com/"]];
+
+    [[webView _inspector] show];
+    TestWebKitAPI::Util::run(&didAttachLocalInspectorCalled);
+
+    auto firstID = [NSUUID UUID].UUIDString;
+    auto secondID = [NSUUID UUID].UUIDString;
+
+    // Normal registration.
+    pendingCallbackWasCalled = false;
+    [[webView _inspector] registerExtensionWithID:firstID displayName:@"FirstExtension" completionHandler:^(NSError * _Nullable error, _WKInspectorExtension * _Nullable extension) {
+        EXPECT_NULL(error);
+        EXPECT_NOT_NULL(extension);
+
+        pendingCallbackWasCalled = true;
+    }];
+    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+
+    // Double registration.
+    pendingCallbackWasCalled = false;
+    [[webView _inspector] registerExtensionWithID:firstID displayName:@"FirstExtension" completionHandler:^(NSError * _Nullable error, _WKInspectorExtension * _Nullable extension) {
+        EXPECT_NOT_NULL(error);
+        EXPECT_NULL(extension);
+        EXPECT_TRUE([error.localizedFailureReason containsString:@"RegistrationFailed"]);
+
+        pendingCallbackWasCalled = true;
+    }];
+    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+
+    // Two registrations.
+    pendingCallbackWasCalled = false;
+    [[webView _inspector] registerExtensionWithID:secondID displayName:@"SecondExtension" completionHandler:^(NSError * _Nullable error, _WKInspectorExtension * _Nullable extension) {
+        EXPECT_NULL(error);
+        EXPECT_NOT_NULL(extension);
+
+        pendingCallbackWasCalled = true;
+    }];
+    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+}
+
+TEST(WKInspectorExtensionHost, UnregisterExtension)
+{
+    resetGlobalState();
+
+    auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]);
+    webViewConfiguration.get().preferences._developerExtrasEnabled = YES;
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto uiDelegate = adoptNS([UIDelegateForTestingInspectorExtensionHost new]);
+
+    [webView setUIDelegate:uiDelegate.get()];
+    [webView loadHTMLString:@"<head><title>Test page to be inspected</title></head><body><p>Filler content</p></body>" baseURL:[NSURL URLWithString:@"http://example.com/"]];
+
+    [[webView _inspector] show];
+    TestWebKitAPI::Util::run(&didAttachLocalInspectorCalled);
+
+    auto firstID = [NSUUID UUID].UUIDString;
+    __block RetainPtr<_WKInspectorExtension> foundExtension;
+
+    // Unregister a known extension.
+    pendingCallbackWasCalled = false;
+    [[webView _inspector] registerExtensionWithID:firstID displayName:@"FirstExtension" completionHandler:^(NSError * _Nullable error, _WKInspectorExtension * _Nullable extension) {
+        EXPECT_NULL(error);
+        EXPECT_NOT_NULL(extension);
+        foundExtension = extension;
+
+        [[webView _inspector] unregisterExtension:foundExtension.get() completionHandler:^(NSError * _Nullable error) {
+            EXPECT_NULL(error);
+
+            pendingCallbackWasCalled = true;
+        }];
+    }];
+    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+    EXPECT_NOT_NULL(foundExtension.get());
+
+    // Re-register an extension.
+    pendingCallbackWasCalled = false;
+    [[webView _inspector] registerExtensionWithID:firstID displayName:@"FirstExtension" completionHandler:^(NSError * _Nullable error, _WKInspectorExtension * _Nullable extension) {
+        EXPECT_NULL(error);
+        EXPECT_NOT_NULL(extension);
+        foundExtension = extension;
+
+        [[webView _inspector] unregisterExtension:foundExtension.get() completionHandler:^(NSError * _Nullable error) {
+            EXPECT_NULL(error);
+
+            pendingCallbackWasCalled = true;
+        }];
+    }];
+    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+    EXPECT_NOT_NULL(foundExtension.get());
+
+    // Unregister an extension twice.
+    pendingCallbackWasCalled = false;
+    [[webView _inspector] unregisterExtension:foundExtension.get() completionHandler:^(NSError * _Nullable error) {
+        EXPECT_NOT_NULL(error);
+        EXPECT_TRUE([error.localizedFailureReason containsString:@"InvalidRequest"]);
+
+        pendingCallbackWasCalled = true;
+    }];
+    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+}
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)