= Rearchitecting the Web Inspector = The main goal here is to divorce the web inspector from having direct access to any objects on the page. This will allow for moving the inspector into it's own process (required for Chromium), but also to increase confidence of security (e.g. JSWrapper objects should no longer be needed). The long-term goal is to have a well-defined API that speaks JSON between the Inspector's JS and the underlying representation of the page. At first, that underlying representation of the page will be written entirely in JS and access the inspected page's DOM directly. Eventually, we can start moving appropriate bits to C++, or in Chromium's case IPC, as necessary. The eventual stack will look something like this: Inspector JS ----------------------------- API Shim JS ----------------------------- InspectorController C++ Give this a generic client (InspectorControllerClient?) that Chromium can implement as IPC. ----------------------------- Possibly an IPC layer ----------------------------- C++ Receives calls from the InspectorControllerClient ----------------------------- Inspected Page's JS == What's There Now == Currently, communication between Inspector and !WebKit occurs via two JS objects: * `InspectorController`, created by !WebKit and populated with methods that JS invokes to talk to WebKit. * `WebInspector`, created on the JS side and used by !WebKit to talk back to inspector. Only a small fraction of `WebInspector`'s methods is actually used for this. For instance, when the messages in the console are cleared by the user, the `InspectorController.clearMessages()` is invoked to reset the corresponding `m_consoleMessages` in !WebKit. Conversely, whenever !WebKit has a new message to display on the console, it creates a `ConsoleMessage` JS object and then invokes `WebInspector.addMessageToConsole()` with that object as an argument. It is up to Inspector's JS code to initialize `WebInspector` object and its methods. = APIs to implement = We'll put all these as objects on the InspectorController. These bits are probably easier to spec out when actually looking at making the change in the code. We can fill in these bits as we get to them. == Message Observers == We will need an API for observing messages by name. There would be two types of messages — notification messages and response messages. Notification messages will be sent to all observers that have registered to receive messages matching a name. Unlike notification messages, response messages are handled for callers of API functions. Any API function that has a response will also take a {{{callbackFunction}}} argument. When a request message is sent for an API call, it will contain a unique identifier. This unique identifier is stored locally and maps to the {{{callbackFunction}}}. When a response message comes back with that unique identifier, the {{{callbackFunction}}} is then called with data from the message passed to the {{{callbackFunction}}} as an argument. == Console == === Functions === {{{InspectorController.Console.evaluate(expression, callbackFunction)}}}[[BR]] ''evaluates the expression in the global context of the inspected page'' {{{InspectorController.Console.fetchMessages(callbackFunction)}}}[[BR]] ''requests an array of all recent messages up to the messageLimit. this is used to populated the Console when opening the Inspector. new messages are gotten from the {{{console:new-messages}}} notification message'' ''NOTE:'' Currently, WebKit simply calls `WebInspector.addMessageToConsole()` for each message when the Inspector opens, so this part of the API will require rework of that logic. {{{InspectorController.Console.clearMessages()}}}[[BR]] ''requests that all messages should be removed'' {{{InspectorController.Console.fetchMessageLimit(callbackFunction)}}}[[BR]] ''requests the current message limit'' {{{InspectorController.Console.setMessageLimit(limit)}}}[[BR]] ''requests the current message limit'' === Response Messages === The {{{evaluate()}}}, {{{fetchMessages()}}} and {{{fetchMessageLimit()}}} functions above will have response messages. {{{console:evaluate}}}[[BR]] ''sent in response to an {{{evaluate()}}} call. contains a value or object representation of the expression's result'' {{{console:messages}}}[[BR]] ''sent in response to a {{{fetchMessages()}}} call. contains an array of console message objects'' {{{console:message-limit}}}[[BR]] ''sent in response to a {{{fetchMessageLimit()}}} call. contains a number'' === Notification Messages === The Console will have a notification message that gets sent to interested observers. {{{console:new-message}}}[[BR]] ''sent when a new message is generated for the inspected page. contains a console message object'' == Profiler == InspectorController.Profiler.? == Resources == InspectorController.Resources.? == DOM == InspectorController.DOM.fetchChildren(node, callbackFunction) InspectorController.DOM.fetchParent(node, callbackFunction) node here is a JS object that has a one-to-one mapping with the DOM node in the page. Everything above this API layer only knows about the node JS object. Somewhere in the implementation of the API there needs to be a mapping. Initially, it can just be an in JS map. Eventually, the map will probably move to C++, at the very least it will for the IPC-based version. == Database == InspectorController.Database.fetchDatabases(callbackFunction) InspectorConteoller.Database.? == Debugger == InspectorController.Debugger.? == Miscellaneous other notes == Objects viewed in the console should be snapshots (i.e. not live). In addition to matching user expectations better, this means we don't need to worry about objects on the page getting GCed. Similarly, any live objects in the debugger should not be GCable. For making sure the inspector has zero impact on page load times and minimal impact on memory usage we agreed on a few UI changes. Network monitoring and possibly debugging should be opt-in per-site. The console should only keep around XXX messages unless the user opts-in to keep more (all?) messages for that site. Currently, Chromium has XXX==100, but that was a relatively arbitrary decision. As a side note, the Chromium/V8 debugger is already zero cost until a debug statement is actually hit, so Chromium doesn't actually care about the debugger being opt-in. == Other random work-in-progress notes == Completely decoupling `InspectorController.cpp` from the JS side will require converting the creation of JS objects on C++ side from property->object->constructor-based approach to more JSON-ey approach, where the objects don't have a specific prototype chain and look more like IPC messages. This in turn will require some refactoring of inspector's JS code to either create prototype-based objects at receiving point or adapt to using new style of messages. ''Perhaps that would make the inspector code a bit cleaner and more JavaScript-ey anyway?'' == BUGS FILED == https://bugs.webkit.org/show_bug.cgi?id=20804 - Objects viewable in debugger should not be garbage collectable[[BR]] https://bugs.webkit.org/show_bug.cgi?id=20803 - Console objects being snapshots[[BR]] https://bugs.webkit.org/show_bug.cgi?id=20800 - Network monitoring opt-in[[BR]] https://bugs.webkit.org/show_bug.cgi?id=20801 - Infinite console logging opt-in[[BR]]