Source/JavaScriptCore/ChangeLog

 12019-11-13 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: allow inspector to pause provisional page load and restore its state
 4 https://bugs.webkit.org/show_bug.cgi?id=204170
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Added an option to Target domain to pause all new targets on start waiting for
 9 explicit 'resume' command from the inspector front-end. This allows to configure
 10 inspector backend (including user agent overrides, breakpoints and instrumentation)
 11 before navigation starts.
 12
 13 * inspector/InspectorTarget.h:
 14 * inspector/agents/InspectorTargetAgent.cpp:
 15 (Inspector::InspectorTargetAgent::willDestroyFrontendAndBackend):
 16 (Inspector::InspectorTargetAgent::setPauseOnStart):
 17 (Inspector::InspectorTargetAgent::resume):
 18 (Inspector::buildTargetInfoObject):
 19 (Inspector::InspectorTargetAgent::targetCreated):
 20 * inspector/agents/InspectorTargetAgent.h:
 21 * inspector/protocol/Target.json:
 22
1232019-11-21 Devin Rousso <drousso@apple.com>
224
325 Web Inspector: removing the blackbox for a specific script doesn't actually remove the blackbox

Source/WebInspectorUI/ChangeLog

 12019-11-13 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: allow inspector to pause provisional page load and restore its state
 4 https://bugs.webkit.org/show_bug.cgi?id=204170
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 All new targets are now automatically paused on start. For such provisional targets target
 9 manager will run regular initilization code (enable agents etc.) and then resume loading of
 10 the target. Responses and events from the target are defferred until the target is committed
 11 and becomes current main target. When the target manager receives event that the provisional
 12 target has been committed all accumulated protocol messages are replayed and going forward all
 13 new missages will be dispatched as usual.
 14
 15 * UserInterface/Controllers/CSSManager.js:
 16 (WI.CSSManager.prototype._resourceContentDidChange.applyStyleSheetChanges.styleSheetFound):
 17 (WI.CSSManager.prototype._resourceContentDidChange.applyStyleSheetChanges):
 18 (WI.CSSManager.prototype._resourceContentDidChange):
 19 (WI.CSSManager.prototype._updateResourceContent.fetchedStyleSheetContent):
 20 * UserInterface/Controllers/TargetManager.js:
 21 (WI.TargetManager):
 22 (WI.TargetManager.prototype.createMultiplexingBackendTarget):
 23 (WI.TargetManager.prototype.targetCreated):
 24 (WI.TargetManager.prototype.didCommitProvisionalTarget):
 25 (WI.TargetManager.prototype.dispatchMessageFromTarget):
 26 (WI.TargetManager.prototype._connectToTarget):
 27 (WI.TargetManager.prototype._destroyTarget):
 28 (WI.TargetManager.prototype._createTarget):
 29 (WI.TargetManager.prototype._checkAndHandlePageTargetTransition):
 30 (WI.TargetManager.prototype._checkAndHandlePageTargetTermination):
 31 * UserInterface/Models/SourceCode.js:
 32 (WI.SourceCode.prototype.get currentRevision):
 33 (WI.SourceCode.prototype.get editableRevision):
 34 (WI.SourceCode.prototype.get content):
 35 (WI.SourceCode.prototype.revisionContentDidChange):
 36 * UserInterface/Protocol/Connection.js:
 37 (InspectorBackend.Connection):
 38 (InspectorBackend.Connection.prototype.addProvisionalMessage):
 39 (InspectorBackend.Connection.prototype.dispatchProvisionalMessages):
 40 * UserInterface/Protocol/PageTarget.js:
 41 (WI.PageTarget):
 42 * UserInterface/Protocol/Target.js:
 43 (WI.Target):
 44 (WI.Target.prototype.get isProvisional):
 45 (WI.Target.prototype.set isProvisional):
 46 * UserInterface/Views/FontResourceContentView.js:
 47 (WI.FontResourceContentView.prototype.dropZoneHandleDrop):
 48 * UserInterface/Views/ImageResourceContentView.js:
 49 (WI.ImageResourceContentView.prototype.dropZoneHandleDrop):
 50 * UserInterface/Views/NavigationSidebarPanel.js:
 51 (WI.NavigationSidebarPanel.prototype._checkElementsForPendingViewStateCookie.treeElementMatchesCookie):
 52 (WI.NavigationSidebarPanel.prototype._checkElementsForPendingViewStateCookie):
 53 * UserInterface/Views/ResourceContentView.js:
 54 (WI.ResourceContentView.prototype._contentAvailable):
 55 (WI.ResourceContentView.prototype._handleImportLocalResourceOverride):
 56 * UserInterface/Views/ScriptContentView.js:
 57 (WI.ScriptContentView.prototype._handleTextEditorContentDidChange):
 58 * UserInterface/Views/TextResourceContentView.js:
 59 (WI.TextResourceContentView.prototype._textEditorContentDidChange):
 60
1612019-11-21 Nikita Vasilyev <nvasilyev@apple.com>
262
363 Web Inspector: Outline sRGB-safe areas on P3 color picker

Source/WebKit/ChangeLog

 12019-11-13 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: allow inspector to pause provisional page load and restore its state
 4 https://bugs.webkit.org/show_bug.cgi?id=204170
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Provisional page loading can be deffered if inspector front-end is connected. This
 9 allows to configure inspector backend in the provisional page before load request
 10 is sent. If inspector front-end is not connected provisional loading will conitinue
 11 exactly as before.
 12
 13 Tests: http/tests/inspector/target/pause-on-inline-debugger-statement.html
 14 http/tests/inspector/target/provisional-load-cancels-previous-load.html
 15
 16 * UIProcess/InspectorTargetProxy.cpp:
 17 (WebKit::InspectorTargetProxy::disconnect):
 18 (WebKit::InspectorTargetProxy::resumeTarget):
 19 * UIProcess/InspectorTargetProxy.h:
 20 * UIProcess/ProvisionalPageProxy.cpp:
 21 (WebKit::ProvisionalPageProxy::ProvisionalPageProxy):
 22 (WebKit::ProvisionalPageProxy::resumeLoading):
 23 (WebKit::ProvisionalPageProxy::runWhenLoadingResumed):
 24 * UIProcess/ProvisionalPageProxy.h:
 25 (WebKit::ProvisionalPageProxy::shouldPauseLoading const):
 26 * UIProcess/WebPageInspectorController.cpp:
 27 (WebKit::WebPageInspectorController::didCreateProvisionalPage):
 28 * UIProcess/WebPageInspectorController.h:
 29 * UIProcess/WebPageProxy.cpp:
 30 (WebKit::WebPageProxy::continueNavigationInNewProcess):
 31 (WebKit::WebPageProxy::speechSynthesisResume):
 32
1332019-11-20 ChangSeok Oh <changseok@webkit.org>
234
335 [GTK] Add ANGLE backend to GTK port

Source/JavaScriptCore/inspector/InspectorTarget.h

@@public:
4747 virtual InspectorTargetType type() const = 0;
4848
4949 virtual bool isProvisional() const { return false; }
 50 bool isPaused() const { return m_pausedOnStart; }
 51 void setPaused(bool paused)
 52 {
 53 m_pausedOnStart = paused;
 54 if (!m_pausedOnStart)
 55 resumeTarget();
 56 }
5057
5158 // Connection management.
5259 virtual void connect(FrontendChannel::ConnectionType) = 0;
5360 virtual void disconnect() = 0;
5461 virtual void sendMessageToTargetBackend(const String&) = 0;
 62
 63private:
 64 virtual void resumeTarget() { }
 65
 66 bool m_pausedOnStart { false };
5567};
5668
5769} // namespace Inspector

Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp

@@void InspectorTargetAgent::willDestroyFrontendAndBackend(DisconnectReason)
5252 disconnectFromTargets();
5353
5454 m_isConnected = false;
 55 m_shouldPauseOnStart = false;
 56}
 57
 58void InspectorTargetAgent::setPauseOnStart(ErrorString&, bool pauseOnStart)
 59{
 60 m_shouldPauseOnStart = pauseOnStart;
 61}
 62
 63void InspectorTargetAgent::resume(ErrorString& error, const String& targetId)
 64{
 65 auto* target = m_targets.get(targetId);
 66 if (!target) {
 67 error = "Missing target for given targetId"_s;
 68 return;
 69 }
 70
 71 if (!target->isPaused()) {
 72 error = "Target for given targetId is not paused"_s;
 73 return;
 74 }
 75
 76 target->setPaused(false);
5577}
5678
5779void InspectorTargetAgent::sendMessageToTarget(ErrorString& errorString, const String& targetId, const String& message)

@@static Ref<Protocol::Target::TargetInfo> buildTargetInfoObject(const InspectorTa
95117 .release();
96118 if (target.isProvisional())
97119 result->setIsProvisional(true);
 120 if (target.isPaused())
 121 result->setIsPaused(true);
98122 return result;
99123}
100124

@@void InspectorTargetAgent::targetCreated(InspectorTarget& target)
106130 if (!m_isConnected)
107131 return;
108132
 133 target.setPaused(m_shouldPauseOnStart);
109134 target.connect(connectionType());
110135
111136 m_frontendDispatcher->targetCreated(buildTargetInfoObject(target));

Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h

@@public:
4949 void willDestroyFrontendAndBackend(DisconnectReason) final;
5050
5151 // TargetBackendDispatcherHandler
 52 void setPauseOnStart(ErrorString&, bool pauseOnStart) override;
 53 void resume(ErrorString&, const String& targetId) override;
5254 void sendMessageToTarget(ErrorString&, const String& targetId, const String& message) final;
5355
5456 // Target lifecycle.

@@private:
7072 Ref<TargetBackendDispatcher> m_backendDispatcher;
7173 HashMap<String, InspectorTarget*> m_targets;
7274 bool m_isConnected { false };
 75 bool m_shouldPauseOnStart { false };
7376};
7477
7578} // namespace Inspector

Source/JavaScriptCore/inspector/protocol/Target.json

1010 "properties": [
1111 { "name": "targetId", "type": "string", "description": "Unique identifier for the target." },
1212 { "name": "type", "type": "string", "enum": ["page", "service-worker", "worker"] },
13  { "name": "isProvisional", "type": "boolean", "optional": true, "description": "True value indicates that this is a provisional page target i.e. Such target may be created when current page starts cross-origin navigation. Eventually each provisional target is either committed and swaps with the current target or gets destroyed, e.g. in case of load request failure." }
 13 { "name": "isProvisional", "type": "boolean", "optional": true, "description": "Whether this is a provisional page target." },
 14 { "name": "isPaused", "type": "boolean", "optional": true, "description": "Whether the target is paused on start and has to be explicitely resumed by inspector." }
1415 ]
1516 }
1617 ],
1718 "commands": [
 19 {
 20 "name": "setPauseOnStart",
 21 "description": "If set to true, new targets will be paused on start waiting for resume command. Other commands can be dispatched on the target before it is resumed.",
 22 "parameters": [
 23 { "name": "pauseOnStart", "type": "boolean", "description": "If set to true, new targets will be paused on start waiting for resume command." }
 24 ]
 25 },
 26 {
 27 "name": "resume",
 28 "description": "Will resume target if it was paused on start.",
 29 "parameters": [
 30 { "name": "targetId", "type": "string" }
 31 ]
 32 },
1833 {
1934 "name": "sendMessageToTarget",
2035 "description": "Send an Inspector Protocol message to be dispatched to a Target's agents.",

Source/WebInspectorUI/UserInterface/Controllers/TargetManager.js

@@WI.TargetManager = class TargetManager extends WI.Object
3333 this._cachedTargetsList = null;
3434 this._seenPageTarget = false;
3535 this._transitionTimeoutIdentifier = undefined;
36 
37  this._provisionalTargetInfos = new Map;
38  this._swappedTargetIds = new Set;
3936 }
4037
4138 // Public

@@WI.TargetManager = class TargetManager extends WI.Object
9491
9592 let target = new WI.MultiplexingBackendTarget;
9693 target.initialize();
 94 // COMPATIBILITY (iOS 13): Target.setPauseOnStart did not exist yet.
 95 if (target.hasCommand("Target.setPauseOnStart"))
 96 target.TargetAgent.setPauseOnStart(true);
9797
9898 this._initializeBackendTarget(target);
9999

@@WI.TargetManager = class TargetManager extends WI.Object
120120
121121 targetCreated(parentTarget, targetInfo)
122122 {
123  this._connectToTarget(parentTarget, targetInfo);
124 
125  this.dispatchEventToListeners(WI.TargetManager.Event.TargetCreated, {targetInfo});
 123 let connection = new InspectorBackend.TargetConnection(parentTarget, targetInfo.targetId);
 124 let subTarget = this._createTarget(parentTarget, targetInfo, connection);
 125 this._checkAndHandlePageTargetTransition(subTarget);
 126 subTarget.initialize();
 127 this.addTarget(subTarget);
126128 }
127129
128130 didCommitProvisionalTarget(parentTarget, previousTargetId, newTargetId)
129131 {
130  this._destroyTarget(previousTargetId);
131  let targetInfo = this._provisionalTargetInfos.get(newTargetId);
132  console.assert(targetInfo);
133  targetInfo.isProvisional = false;
134  this._provisionalTargetInfos.delete(newTargetId);
135  this._connectToTarget(parentTarget, targetInfo);
136  console.assert(!this._swappedTargetIds.has(previousTargetId));
137  this._swappedTargetIds.add(previousTargetId);
138 
139  this.dispatchEventToListeners(WI.TargetManager.Event.DidCommitProvisionalTarget, {previousTargetId, targetInfo});
 132 this.targetDestroyed(previousTargetId);
 133 let target = this._targets.get(newTargetId);
 134 console.assert(target);
 135 if (!target)
 136 return;
 137
 138 target.isProvisional = false;
 139 this._checkAndHandlePageTargetTransition(target);
 140 target.connection.dispatchProvisionalMessages();
 141
 142 this.dispatchEventToListeners(WI.TargetManager.Event.DidCommitProvisionalTarget, {previousTargetId, target});
140143 }
141144
142145 targetDestroyed(targetId)
143146 {
144  this._destroyTarget(targetId);
 147 let target = this._targets.get(targetId);
 148 if (!target)
 149 return;
145150
146  this.dispatchEventToListeners(WI.TargetManager.Event.TargetDestroyed, {targetId});
 151 this._checkAndHandlePageTargetTermination(target);
 152 this.removeTarget(target);
147153 }
148154
149155 dispatchMessageFromTarget(targetId, message)
150156 {
151  if (this._provisionalTargetInfos.has(targetId))
152  return;
153 
154157 let target = this._targets.get(targetId);
155158 console.assert(target);
156159 if (!target)
157160 return;
158161
159  target.connection.dispatch(message);
 162 if (target.isProvisional)
 163 target.connection.addProvisionalMessage(message);
 164 else
 165 target.connection.dispatch(message);
160166 }
161167
162168 // Private
163169
164  _connectToTarget(parentTarget, targetInfo)
165  {
166  console.assert(!this._provisionalTargetInfos.has(targetInfo.targetId));
167 
168  // COMPATIBILITY (iOS 13.0): `Target.TargetInfo.isProvisional` did not exist yet.
169  if (targetInfo.isProvisional) {
170  this._provisionalTargetInfos.set(targetInfo.targetId, targetInfo);
171  return;
172  }
173 
174  console.assert(parentTarget.hasCommand("Target.sendMessageToTarget"));
175  let connection = new InspectorBackend.TargetConnection;
176  let subTarget = this._createTarget(parentTarget, targetInfo, connection);
177  this._checkAndHandlePageTargetTransition(subTarget);
178  subTarget.initialize();
179 
180  this.addTarget(subTarget);
181  }
182 
183  _destroyTarget(targetId)
184  {
185  if (this._provisionalTargetInfos.delete(targetId))
186  return;
187 
188  if (this._swappedTargetIds.delete(targetId))
189  return;
190 
191  let target = this._targets.get(targetId);
192  this._checkAndHandlePageTargetTermination(target);
193  this.removeTarget(target);
194  }
195 
196170 _createTarget(parentTarget, targetInfo, connection)
197171 {
198  let {targetId, type} = targetInfo;
 172 // COMPATIBILITY (iOS 13.0): `Target.TargetInfo.isPaused` did not exist yet.
 173 let {targetId, type, isPaused} = targetInfo;
199174
200175 switch (type) {
201176 case InspectorBackend.Enum.Target.TargetInfoType.Page:
202  return new WI.PageTarget(parentTarget, targetId, WI.UIString("Page"), connection);
 177 return new WI.PageTarget(parentTarget, targetId, WI.UIString("Page"), connection, targetInfo.isProvisional, isPaused);
203178 case InspectorBackend.Enum.Target.TargetInfoType.Worker:
204  return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("Worker"), connection);
 179 return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("Worker"), connection, isPaused);
205180 case "serviceworker": // COMPATIBILITY (iOS 13): "serviceworker" was renamed to "service-worker".
206181 case InspectorBackend.Enum.Target.TargetInfoType.ServiceWorker:
207  return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("ServiceWorker"), connection);
 182 return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("ServiceWorker"), connection, isPaused);
208183 }
209184
210185 throw "Unknown Target type: " + type;

@@WI.TargetManager = class TargetManager extends WI.Object
215190 if (target.type !== WI.TargetType.Page)
216191 return;
217192
 193 if (target.isProvisional)
 194 return;
 195
218196 // First page target.
219197 if (!WI.pageTarget && !this._seenPageTarget) {
220198 this._seenPageTarget = true;

@@WI.TargetManager = class TargetManager extends WI.Object
231209 if (target.type !== WI.TargetType.Page)
232210 return;
233211
 212 if (target.isProvisional)
 213 return;
 214
234215 console.assert(target === WI.pageTarget);
235216 console.assert(this._seenPageTarget);
236217

@@WI.TargetManager = class TargetManager extends WI.Object
315296WI.TargetManager.Event = {
316297 TargetAdded: Symbol("target-manager-target-added"),
317298 TargetRemoved: Symbol("target-manager-target-removed"),
318 
319  TargetCreated: "target-manager-target-created",
320299 DidCommitProvisionalTarget: "target-manager-provisional-target-committed",
321  TargetDestroyed: "target-manager-target-detroyed",
322300};

Source/WebInspectorUI/UserInterface/Controllers/WorkerManager.js

@@WI.WorkerManager = class WorkerManager extends WI.Object
4646 {
4747 console.assert(target.hasCommand("Worker.sendMessageToWorker"));
4848 let connection = new InspectorBackend.WorkerConnection;
49  let workerTarget = new WI.WorkerTarget(target, workerId, url, connection);
 49 const isPaused = false;
 50 let workerTarget = new WI.WorkerTarget(target, workerId, url, connection, isPaused);
5051 workerTarget.initialize();
5152
5253 WI.targetManager.addTarget(workerTarget);

Source/WebInspectorUI/UserInterface/Protocol/Connection.js

@@InspectorBackend.Connection = class InspectorBackendConnection
3939 this._pendingResponses = new Map;
4040 this._deferredCallbacks = [];
4141 this._target = null;
 42 this._provisionalMessages = [];
4243 }
4344
4445 // Public

@@InspectorBackend.Connection = class InspectorBackendConnection
5455 this._target = target;
5556 }
5657
 58 addProvisionalMessage(message)
 59 {
 60 this._provisionalMessages.push(message);
 61 }
 62
 63 dispatchProvisionalMessages()
 64 {
 65 console.assert(this.target);
 66 console.assert(!this.target.isProvisional);
 67 for (let message of this._provisionalMessages)
 68 this.dispatch(message);
 69 this._provisionalMessages = null;
 70 }
 71
5772 dispatch(message)
5873 {
5974 let messageObject = typeof message === "string" ? JSON.parse(message) : message;

Source/WebInspectorUI/UserInterface/Protocol/DirectBackendTarget.js

@@WI.DirectBackendTarget = class DirectBackendTarget extends WI.Target
3333 const parentTarget = null;
3434 const targetId = "direct";
3535 let {type, displayName} = DirectBackendTarget.connectionInfoForDebuggable();
36  super(parentTarget, targetId, displayName, type, InspectorBackend.backendConnection);
 36 const isPaused = false;
 37 super(parentTarget, targetId, displayName, type, InspectorBackend.backendConnection, isPaused);
3738
3839 this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, displayName, true, null);
3940 this._mainResource = null;

Source/WebInspectorUI/UserInterface/Protocol/MultiplexingBackendTarget.js

@@WI.MultiplexingBackendTarget = class MultiplexingBackendTarget extends WI.Target
3434 {
3535 const parentTarget = null;
3636 const targetId = "multi";
37  super(parentTarget, targetId, WI.UIString("Web Page"), WI.TargetType.WebPage, InspectorBackend.backendConnection);
 37 const isPaused = false;
 38 super(parentTarget, targetId, WI.UIString("Web Page"), WI.TargetType.WebPage, InspectorBackend.backendConnection, isPaused);
3839
3940 console.assert(Array.shallowEqual(Object.keys(this._agents), ["Target"]), "A WebPage target should only have a single agent.");
4041 }

Source/WebInspectorUI/UserInterface/Protocol/PageTarget.js

2525
2626WI.PageTarget = class PageTarget extends WI.Target
2727{
28  constructor(parentTarget, targetId, name, connection)
 28 constructor(parentTarget, targetId, name, connection, isProvisional, isPaused)
2929 {
30  super(parentTarget, targetId, name, WI.TargetType.Page, connection);
 30 super(parentTarget, targetId, name, WI.TargetType.Page, connection, isPaused);
3131
3232 const isPageContext = true;
3333 this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, isPageContext, null);
 34 this.isProvisional = isProvisional;
3435 }
3536};

Source/WebInspectorUI/UserInterface/Protocol/Target.js

2525
2626WI.Target = class Target extends WI.Object
2727{
28  constructor(parentTarget, identifier, name, type, connection)
 28 constructor(parentTarget, identifier, name, type, connection, isPaused)
2929 {
3030 console.assert(parentTarget === null || parentTarget instanceof WI.Target);
3131 super();

@@WI.Target = class Target extends WI.Object
3939 this._mainResource = null;
4040 this._resourceCollection = new WI.ResourceCollection;
4141 this._extraScriptCollection = new WI.ScriptCollection;
 42 this._isProvisional = false;
 43 this._isPaused = isPaused;
4244
4345 this._supportedCommandParameters = new Map;
4446 this._supportedEventParameters = new Map;

@@WI.Target = class Target extends WI.Object
9698 if (this.hasCommand("Inspector.initialized"))
9799 this.InspectorAgent.initialized();
98100 });
 101
 102 if (this._isPaused) {
 103 console.assert(this._parentTarget.hasCommand("Target.resume"));
 104 this._parentTarget.TargetAgent.resume(this._identifier)
 105 .then(() => {
 106 this._isPaused = false;
 107 }).catch((error) => {
 108 // Ignore errors if the target was destroyed after the command was sent.
 109 if (this.isDestroyed)
 110 return;
 111
 112 WI.reportInternalError(error);
 113 });
 114 }
99115 }
100116
101117 activateExtraDomain(domainName)

@@WI.Target = class Target extends WI.Object
105121 this._agents[domainName] = InspectorBackend._makeAgent(domainName, this);
106122 }
107123
 124 get isPaused() { return this._isPaused; }
 125
108126 // Agents
109127
110128 get AnimationAgent() { return this._agents.Animation; }

@@WI.Target = class Target extends WI.Object
169187 get name() { return this._name; }
170188 set name(name) { this._name = name; }
171189
 190 get isProvisional() { return this._isProvisional; }
 191 set isProvisional(value) { this._isProvisional = value; }
 192
172193 get type() { return this._type; }
173194 get connection() { return this._connection; }
174195 get executionContext() { return this._executionContext; }

Source/WebInspectorUI/UserInterface/Protocol/WorkerTarget.js

2525
2626WI.WorkerTarget = class WorkerTarget extends WI.Target
2727{
28  constructor(parentTarget, workerId, name, connection)
 28 constructor(parentTarget, workerId, name, connection, isPaused)
2929 {
30  super(parentTarget, workerId, name, WI.TargetType.Worker, connection);
 30 super(parentTarget, workerId, name, WI.TargetType.Worker, connection, isPaused);
3131
3232 const isPageContext = false;
3333 this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, isPageContext, null);

Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js

@@WI.NavigationSidebarPanel = class NavigationSidebarPanel extends WI.SidebarPanel
705705 return false;
706706
707707 if (matchTypeOnly)
708  return true;
 708 return !!typeIdentifier;
709709
710710 var candidateObjectCookie = {};
711711 if (representedObject.saveIdentityToCookie)

Source/WebKit/UIProcess/InspectorTargetProxy.cpp

@@void InspectorTargetProxy::disconnect()
7676
7777 if (m_page.hasRunningProcess())
7878 m_page.process().send(Messages::WebPage::DisconnectInspector(identifier()), m_page.webPageID());
 79
 80 if (isPaused())
 81 setPaused(false);
7982}
8083
8184void InspectorTargetProxy::sendMessageToTargetBackend(const String& message)

@@bool InspectorTargetProxy::isProvisional() const
100103 return !!m_provisionalPage;
101104}
102105
 106void InspectorTargetProxy::resumeTarget()
 107{
 108 if (m_provisionalPage)
 109 m_provisionalPage->continueLoading();
 110}
 111
103112} // namespace WebKit

Source/WebKit/UIProcess/InspectorTargetProxy.h

@@public:
5757 void sendMessageToTargetBackend(const String&) override;
5858
5959private:
 60 void resumeTarget() override;
 61
6062 WebPageProxy& m_page;
6163 String m_identifier;
6264 Inspector::InspectorTargetType m_type;

Source/WebKit/UIProcess/ProvisionalPageProxy.cpp

@@ProvisionalPageProxy::ProvisionalPageProxy(WebPageProxy& page, Ref<WebProcessPro
8787
8888 initializeWebPage();
8989
90  m_page.inspectorController().didCreateProvisionalPage(*this);
 90 m_loadingPaused = m_page.inspectorController().interceptProvisionalPage(*this) == WebPageInspectorController::PauseLoading::Yes;
9191}
9292
9393ProvisionalPageProxy::~ProvisionalPageProxy()

@@std::unique_ptr<DrawingAreaProxy> ProvisionalPageProxy::takeDrawingArea()
117117 return WTFMove(m_drawingArea);
118118}
119119
 120void ProvisionalPageProxy::continueLoading()
 121{
 122 if (m_loadingContinuation) {
 123 m_loadingContinuation();
 124 m_loadingContinuation = nullptr;
 125 }
 126 m_loadingPaused = false;
 127}
 128
 129void ProvisionalPageProxy::continueLoadingWhenResumedByInspector(WTF::Function<void()>&& callback)
 130{
 131 m_loadingContinuation = WTFMove(callback);
 132}
 133
120134void ProvisionalPageProxy::cancel()
121135{
122136 // If the provisional load started, then indicate that it failed due to cancellation by calling didFailProvisionalLoadForFrame().

Source/WebKit/UIProcess/ProvisionalPageProxy.h

@@public:
9090
9191 void processDidTerminate();
9292
 93 void continueLoading();
 94 bool shouldPauseLoadingForInspector() const { return m_loadingPaused; }
 95 void continueLoadingWhenResumedByInspector(WTF::Function<void()>&&);
 96
9397private:
9498 // IPC::MessageReceiver
9599 void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;

@@private:
138142 ProcessSwapRequestedByClient m_processSwapRequestedByClient;
139143 bool m_wasCommitted { false };
140144 URL m_provisionalLoadURL;
 145 WTF::Function<void()> m_loadingContinuation;
 146 bool m_loadingPaused { false };
141147
142148#if PLATFORM(COCOA)
143149 Vector<uint8_t> m_accessibilityToken;

Source/WebKit/UIProcess/WebPageInspectorController.cpp

@@void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta
167167 m_targetAgent->sendMessageFromTargetToFrontend(targetId, message);
168168}
169169
170 void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage)
 170WebPageInspectorController::PauseLoading WebPageInspectorController::interceptProvisionalPage(ProvisionalPageProxy& provisionalPage)
171171{
172  addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page));
 172 auto target = InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page);
 173 auto* targetPtr = target.get();
 174 addTarget(WTFMove(target));
 175 return targetPtr->isPaused() ? WebPageInspectorController::PauseLoading::Yes : WebPageInspectorController::PauseLoading::No;
173176}
174177
175178void WebPageInspectorController::willDestroyProvisionalPage(const ProvisionalPageProxy& provisionalPage)

Source/WebKit/UIProcess/WebPageInspectorController.h

@@public:
6666 void destroyInspectorTarget(const String& targetId);
6767 void sendMessageToInspectorFrontend(const String& targetId, const String& message);
6868
69  void didCreateProvisionalPage(ProvisionalPageProxy&);
 69 enum class PauseLoading { No, Yes };
 70 PauseLoading interceptProvisionalPage(ProvisionalPageProxy&);
7071 void willDestroyProvisionalPage(const ProvisionalPageProxy&);
7172 void didCommitProvisionalPage(WebCore::PageIdentifier oldWebPageID, WebCore::PageIdentifier newWebPageID);
7273

Source/WebKit/UIProcess/WebPageProxy.cpp

@@void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, s
30963096
30973097 m_provisionalPage = makeUnique<ProvisionalPageProxy>(*this, newProcess.copyRef(), WTFMove(suspendedPage), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient);
30983098
3099  if (auto* item = navigation.targetItem()) {
3100  LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
 3099 auto continuation = [this, navigation = makeRef(navigation), newProcess = WTFMove(newProcess), websitePolicies = WTFMove(websitePolicies)]() mutable {
 3100 if (auto* item = navigation->targetItem()) {
 3101 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
31013102
3102  auto transaction = m_pageLoadState.transaction();
3103  m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), item->url() });
 3103 auto transaction = m_pageLoadState.transaction();
 3104 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), item->url() });
31043105
3105  m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
3106  return;
3107  }
 3106 m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
 3107 return;
 3108 }
31083109
3109  if (m_backForwardList->currentItem() && (navigation.lockBackForwardList() == LockBackForwardList::Yes || navigation.lockHistory() == LockHistory::Yes)) {
3110  // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update
3111  // it instead of creating a new one.
3112  newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_provisionalPage->webPageID());
3113  }
 3110 if (m_backForwardList->currentItem() && (navigation->lockBackForwardList() == LockBackForwardList::Yes || navigation->lockHistory() == LockHistory::Yes)) {
 3111 // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update
 3112 // it instead of creating a new one.
 3113 newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_provisionalPage->webPageID());
 3114 }
31143115
3115  // FIXME: Work out timing of responding with the last policy delegate, etc
3116  ASSERT(!navigation.currentRequest().isEmpty());
3117  if (auto& substituteData = navigation.substituteData())
3118  m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies));
 3116 // FIXME: Work out timing of responding with the last policy delegate, etc
 3117 ASSERT(!navigation->currentRequest().isEmpty());
 3118 if (auto& substituteData = navigation->substituteData())
 3119 m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies));
 3120 else
 3121 m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
 3122 };
 3123 if (m_provisionalPage->shouldPauseLoadingForInspector())
 3124 m_provisionalPage->continueLoadingWhenResumedByInspector(WTFMove(continuation));
31193125 else
3120  m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
 3126 continuation();
31213127}
31223128
31233129bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const

LayoutTests/ChangeLog

 12019-11-13 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: allow inspector to pause provisional page load and restore its state
 4 https://bugs.webkit.org/show_bug.cgi?id=204170
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Test that provisional loading which starts before previos provisional loading
 9 commits will be correctly handled by the insepctor.
 10
 11 Test that script execution will break on debugger statement in inline scripts in
 12 case of cross origin navigation and PSON.
 13
 14 * http/tests/inspector/target/pause-on-inline-debugger-statement-expected.txt: Added.
 15 * http/tests/inspector/target/pause-on-inline-debugger-statement.html: Added.
 16 * http/tests/inspector/target/provisional-load-cancels-previous-load-expected.txt: Added.
 17 * http/tests/inspector/target/provisional-load-cancels-previous-load.html: Added.
 18 * http/tests/inspector/target/resources/inline-debugger-statement.html: Added.
 19 * http/tests/inspector/target/target-events-for-provisional-page.html:
 20
1212019-11-21 Simon Fraser <simon.fraser@apple.com>
222
323 Flaky Test: compositing/backing/backing-store-attachment-with-rotation.html

LayoutTests/http/tests/inspector/target/pause-on-inline-debugger-statement-expected.txt

 1ALERT: PASS: Should pause on debugger statement.
 2Test page used to check that execution will break on inline 'debugger' statement after cross-origin navigation.

LayoutTests/http/tests/inspector/target/pause-on-inline-debugger-statement.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<meta charset="utf-8">
 5<script src="../resources/inspector-test.js"></script>
 6<script>
 7function test()
 8{
 9 let suite = InspectorTest.createAsyncSuite("Target.PSON");
 10
 11 suite.addTestCase({
 12 name: "InlineDebuggerStatement",
 13 description: "Check that new provisional page can be paused before navigation.",
 14 test(resolve, reject) {
 15 WI.debuggerManager.awaitEvent(WI.DebuggerManager.Event.Paused)
 16 .then(() => {
 17 InspectorTest.pass(`Should pause on debugger statement.`);
 18
 19 // Wait for page reload event to avoid race between test results flushing and the test completion.
 20 let pageLoadPromise = InspectorTest.awaitEvent(FrontendTestHarness.Event.TestPageDidLoad);
 21 //WI.mainTarget.DebuggerAgent.
 22 Promise.resolve().then(() => {
 23 WI.debuggerManager.resume();
 24 });
 25 return pageLoadPromise;
 26 })
 27 .then(resolve);
 28
 29
 30 const url = "http://localhost:8000/inspector/target/resources/inline-debugger-statement.html";
 31 WI.mainTarget.PageAgent.navigate(url);
 32 }
 33 });
 34
 35 suite.runTestCasesAndFinish();
 36}
 37</script>
 38</head>
 39<body onload="runTest()">
 40<p>Test that execution will break on inline 'debugger' statement after cross-origin navigation.</p>
 41</body>
 42</html>

LayoutTests/http/tests/inspector/target/provisional-load-cancels-previous-load-expected.txt

 1Test that two consequtive cross domain navigation requests will result in two provisional targets being created, first of which is later destroyed and the second is committed.
 2
 3
 4== Running test suite: Target.PSON
 5-- Running test case: ProvisionalPagePaused
 6Current target is 1.
 7PASS: Should receive TargetAdded event for target 2.
 8PASS: Target 2 should be provisional.
 9PASS: Target 2 should be paused on start.
 10PASS: Should receive TargetRemoved event for target 2
 11PASS: Should receive TargetAdded event for target 3.
 12PASS: Target 3 should be provisional.
 13PASS: Target 3 should be paused on start.
 14PASS: Should receive TargetRemoved event for target 1
 15PASS: Should receive DidCommitProvisionalTarget event 1 => 3.
 16PASS: Should have seen 3 different targets.
 17

LayoutTests/http/tests/inspector/target/provisional-load-cancels-previous-load.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<meta charset="utf-8">
 5<script src="../resources/inspector-test.js"></script>
 6<script>
 7function test()
 8{
 9 let lastAssignedId = 0;
 10 let targetToId = new Map;
 11 function stableTargetId(targetId)
 12 {
 13 let id = targetToId.get(targetId);
 14 if (!id) {
 15 id = ++lastAssignedId;
 16 targetToId.set(targetId, id);
 17 }
 18 return id;
 19 }
 20
 21 let suite = InspectorTest.createAsyncSuite("Target.PSON");
 22
 23 suite.addTestCase({
 24 name: "ProvisionalPagePaused",
 25 description: "Check that new provisional page can be paused before navigation.",
 26 test(resolve, reject) {
 27 InspectorTest.log(`Current target is ${stableTargetId(WI.mainTarget.identifier)}.`);
 28
 29 WI.targetManager.addEventListener(WI.TargetManager.Event.TargetAdded, (event) => {
 30 let target = event.data.target;
 31 let targetId = stableTargetId(target.identifier);
 32 InspectorTest.pass(`Should receive TargetAdded event for target ${targetId}.`);
 33 InspectorTest.expectTrue(target.isProvisional, `Target ${targetId} should be provisional.`);
 34 InspectorTest.expectTrue(target.isPaused, `Target ${targetId} should be paused on start.`);
 35 });
 36
 37 WI.targetManager.addEventListener(WI.TargetManager.Event.DidCommitProvisionalTarget, (event) => {
 38 let {previousTargetId, target} = event.data;
 39 InspectorTest.pass(`Should receive DidCommitProvisionalTarget event ${stableTargetId(previousTargetId)} => ${stableTargetId(target.identifier)}.`);
 40 });
 41
 42 WI.targetManager.addEventListener(WI.TargetManager.Event.TargetRemoved, (event) =>{
 43 let targetId = stableTargetId(event.data.target.identifier);
 44 InspectorTest.pass(`Should receive TargetRemoved event for target ${targetId}`);
 45 });
 46
 47 // Wait for page reload event to avoid race between test results flushing and the test completion.
 48 InspectorTest.awaitEvent(FrontendTestHarness.Event.TestPageDidLoad)
 49 .then(() => {
 50 InspectorTest.expectEqual(lastAssignedId, 3, `Should have seen 3 different targets.`);
 51 })
 52 .then(resolve);
 53
 54 // Send two consequtive navigation requests. The latter will cancel provisional
 55 // load of the former.
 56 const url = "http://localhost:8000/inspector/target/provisional-load-cancels-previous-load.html";
 57 WI.mainTarget.PageAgent.navigate(url);
 58 WI.mainTarget.PageAgent.navigate(url);
 59 }
 60 });
 61
 62 suite.runTestCasesAndFinish();
 63}
 64</script>
 65</head>
 66<body onload="runTest()">
 67<p>Test that two consequtive cross domain navigation requests will result in two
 68provisional targets being created, first of which is later destroyed and the second
 69is committed.</p>
 70</body>
 71</html>

LayoutTests/http/tests/inspector/target/resources/inline-debugger-statement.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<meta charset="utf-8">
 5<script src="../../resources/inspector-test.js"></script>
 6<script>
 7
 8debugger;
 9
 10function test()
 11{
 12 InspectorTest.fail("This code should never actually run. It is here becase inspector-test.js harness requires a test() function.");
 13}
 14</script>
 15</head>
 16<body onload="runTest()">
 17<p>Test page used to check that execution will break on inline 'debugger' statement after cross-origin navigation.</p>
 18</body>
 19</html>

LayoutTests/http/tests/inspector/target/target-events-for-provisional-page-expected.txt

@@Test that cross domain navigation results in the following sequence of events in
66
77== Running test suite: Target.PSON
88-- Running test case: ProvisionalPageTarget
9 PASS: Should receive targetCreated event.
 9PASS: Should receive TargetAdded event.
1010PASS: Target should be provisional.
11 PASS: Should receive didCommitProvisionalTarget event.
 11PASS: Should receive TargetRemoved event.
 12PASS: Destroyed target should be previous target.
 13PASS: Should receive DidCommitProvisionalTarget event.
1214PASS: Previous target should be the current one.
1315PASS: Committed target should match provisional target.
14 PASS: Should receive targetDestroyed event.
15 PASS: Destroyed target should be previous target.
1616

LayoutTests/http/tests/inspector/target/target-events-for-provisional-page.html

@@function test()
1313 description: "Check that a new target will be created for provisional page.",
1414 test(resolve, reject) {
1515 const mainTargetId = WI.mainTarget.identifier;
16  let newTargetId;
 16 let newTarget;
1717 InspectorTest.assert(mainTargetId);
1818 let reloadPromise = InspectorTest.awaitEvent(FrontendTestHarness.Event.TestPageDidLoad);
1919
20  WI.targetManager.addEventListener(WI.TargetManager.Event.TargetCreated, (event) => {
21  let {targetInfo} = event.data;
22  newTargetId = targetInfo.targetId;
23  InspectorTest.pass(`Should receive targetCreated event.`);
24  InspectorTest.expectTrue(targetInfo.isProvisional, "Target should be provisional.");
 20 WI.targetManager.addEventListener(WI.TargetManager.Event.TargetAdded, (event) => {
 21 newTarget = event.data.target;
 22 InspectorTest.pass(`Should receive TargetAdded event.`);
 23 InspectorTest.expectTrue(newTarget.isProvisional, "Target should be provisional.");
2524 });
2625
2726 WI.targetManager.addEventListener(WI.TargetManager.Event.DidCommitProvisionalTarget, (event) => {
28  let {previousTargetId, targetInfo} = event.data;
29  InspectorTest.pass(`Should receive didCommitProvisionalTarget event.`);
 27 let {previousTargetId, target} = event.data;
 28 InspectorTest.pass(`Should receive DidCommitProvisionalTarget event.`);
3029 InspectorTest.expectEqual(previousTargetId, mainTargetId, "Previous target should be the current one.");
31  InspectorTest.expectEqual(targetInfo.targetId, newTargetId, "Committed target should match provisional target.");
 30 InspectorTest.expectEqual(target, newTarget, "Committed target should match provisional target.");
3231 });
3332
34  WI.targetManager.addEventListener(WI.TargetManager.Event.TargetDestroyed, (event) =>{
35  let {targetId} = event.data;
36  InspectorTest.pass(`Should receive targetDestroyed event.`);
37  InspectorTest.expectEqual(targetId, mainTargetId, "Destroyed target should be previous target.");
 33 WI.targetManager.addEventListener(WI.TargetManager.Event.TargetRemoved, (event) =>{
 34 let target = event.data.target;
 35 InspectorTest.pass(`Should receive TargetRemoved event.`);
 36 InspectorTest.expectEqual(target.identifier, mainTargetId, "Destroyed target should be previous target.");
3837
3938 // Wait for page reload event to avoid race between test results flushing and the test completion.
4039 reloadPromise.then(resolve);