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-12-02 Saam Barati <sbarati@apple.com>
224
325 PropertySlot should not have Customs have a PropertyOffset of zero

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-12-02 Nikita Vasilyev <nvasilyev@apple.com>
262
363 Web Inspector: Provide UI to convert between sRGB and p3 color spaces

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-12-03 Chris Dumez <cdumez@apple.com>
234
335 PageConfiguration::alternativeTextClient should use a smart pointer

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_isPaused; }
 51 void setPaused(bool paused)
 52 {
 53 m_isPaused = paused;
 54 if (!m_isPaused && m_resumeCallback) {
 55 m_resumeCallback();
 56 m_resumeCallback = nullptr;
 57 }
 58 }
 59 void setResumeCallback(WTF::Function<void()>&& callback) { m_resumeCallback = WTFMove(callback); }
5060
5161 // Connection management.
5262 virtual void connect(FrontendChannel::ConnectionType) = 0;
5363 virtual void disconnect() = 0;
5464 virtual void sendMessageToTargetBackend(const String&) = 0;
 65
 66private:
 67 WTF::Function<void()> m_resumeCallback;
 68 bool m_isPaused { false };
5569};
5670
5771} // 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& errorString, const String& targetId)
 64{
 65 auto* target = m_targets.get(targetId);
 66 if (!target) {
 67 errorString = "Missing target for given targetId"_s;
 68 return;
 69 }
 70
 71 if (!target->isPaused()) {
 72 errorString = "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));

@@void InspectorTargetAgent::targetDestroyed(InspectorTarget& target)
118143 if (!m_isConnected)
119144 return;
120145
121  target.disconnect();
122 
123146 m_frontendDispatcher->targetDestroyed(target.identifier());
124147}
125148

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/WebCore/inspector/InspectorFrontendHost.cpp

@@void InspectorFrontendHost::close(const String&)
370370
371371void InspectorFrontendHost::sendMessageToBackend(const String& message)
372372{
 373 fprintf(stderr, "sendMessageToBackend %s\n", message.left(200).ascii().data());
373374 if (m_client)
374375 m_client->sendMessageToBackend(message);
375376}

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
120117
121118 targetCreated(parentTarget, targetInfo)
122119 {
123  this._connectToTarget(parentTarget, targetInfo);
124 
125  this.dispatchEventToListeners(WI.TargetManager.Event.TargetCreated, {targetInfo});
 120 let connection = new InspectorBackend.TargetConnection(parentTarget, targetInfo.targetId);
 121 let subTarget = this._createTarget(parentTarget, targetInfo, connection);
 122 this._checkAndHandlePageTargetTransition(subTarget);
 123 subTarget.initialize();
 124 this.addTarget(subTarget);
126125 }
127126
128127 didCommitProvisionalTarget(parentTarget, previousTargetId, newTargetId)
129128 {
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});
 129 this.targetDestroyed(previousTargetId);
 130 let target = this._targets.get(newTargetId);
 131 console.assert(target);
 132 if (!target)
 133 return;
 134
 135 target.didCommitProvisionalTarget();
 136 this._checkAndHandlePageTargetTransition(target);
 137 target.connection.dispatchProvisionalMessages();
 138
 139 this.dispatchEventToListeners(WI.TargetManager.Event.DidCommitProvisionalTarget, {previousTargetId, target});
140140 }
141141
142142 targetDestroyed(targetId)
143143 {
144  this._destroyTarget(targetId);
 144 let target = this._targets.get(targetId);
 145 if (!target)
 146 return;
145147
146  this.dispatchEventToListeners(WI.TargetManager.Event.TargetDestroyed, {targetId});
 148 this._checkAndHandlePageTargetTermination(target);
 149 this.removeTarget(target);
147150 }
148151
149152 dispatchMessageFromTarget(targetId, message)
150153 {
151  if (this._provisionalTargetInfos.has(targetId))
152  return;
153 
154154 let target = this._targets.get(targetId);
155155 console.assert(target);
156156 if (!target)
157157 return;
158158
159  target.connection.dispatch(message);
 159 if (target.isProvisional)
 160 target.connection.addProvisionalMessage(message);
 161 else
 162 target.connection.dispatch(message);
160163 }
161164
162165 // Private
163166
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 
196167 _createTarget(parentTarget, targetInfo, connection)
197168 {
198  let {targetId, type} = targetInfo;
 169 // COMPATIBILITY (iOS 13.0): `Target.TargetInfo.isProvisional` and `Target.TargetInfo.isPaused` did not exist yet.
 170 let {targetId, type, isProvisional, isPaused} = targetInfo;
199171
200172 switch (type) {
201173 case InspectorBackend.Enum.Target.TargetInfoType.Page:
202  return new WI.PageTarget(parentTarget, targetId, WI.UIString("Page"), connection);
 174 return new WI.PageTarget(parentTarget, targetId, WI.UIString("Page"), connection, {isProvisional, isPaused});
203175 case InspectorBackend.Enum.Target.TargetInfoType.Worker:
204  return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("Worker"), connection);
 176 return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("Worker"), connection, {isPaused});
205177 case "serviceworker": // COMPATIBILITY (iOS 13): "serviceworker" was renamed to "service-worker".
206178 case InspectorBackend.Enum.Target.TargetInfoType.ServiceWorker:
207  return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("ServiceWorker"), connection);
 179 return new WI.WorkerTarget(parentTarget, targetId, WI.UIString("ServiceWorker"), connection, {isPaused});
208180 }
209181
210182 throw "Unknown Target type: " + type;

@@WI.TargetManager = class TargetManager extends WI.Object
215187 if (target.type !== WI.TargetType.Page)
216188 return;
217189
 190 if (target.isProvisional)
 191 return;
 192
218193 // First page target.
219194 if (!WI.pageTarget && !this._seenPageTarget) {
220195 this._seenPageTarget = true;

@@WI.TargetManager = class TargetManager extends WI.Object
231206 if (target.type !== WI.TargetType.Page)
232207 return;
233208
 209 if (target.isProvisional)
 210 return;
 211
234212 console.assert(target === WI.pageTarget);
235213 console.assert(this._seenPageTarget);
236214

@@WI.TargetManager = class TargetManager extends WI.Object
317295WI.TargetManager.Event = {
318296 TargetAdded: Symbol("target-manager-target-added"),
319297 TargetRemoved: Symbol("target-manager-target-removed"),
320 
321  TargetCreated: "target-manager-target-created",
322298 DidCommitProvisionalTarget: "target-manager-provisional-target-committed",
323  TargetDestroyed: "target-manager-target-detroyed",
324299};

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/MultiplexingBackendTarget.js

@@WI.MultiplexingBackendTarget = class MultiplexingBackendTarget extends WI.Target
4343
4444 initialize()
4545 {
46  // Intentionally do nothing, including not calling super.
47  // No agents other than the TargetAgent, nothing to initialize.
 46 // Intentionally not calling super. No agents other than the TargetAgent.
 47
 48 // COMPATIBILITY (iOS 13): Target.setPauseOnStart did not exist yet.
 49 if (this.hasCommand("Target.setPauseOnStart"))
 50 this.TargetAgent.setPauseOnStart(true);
4851 }
4952
5053 // Protected (Target)

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, options = {})
2929 {
30  super(parentTarget, targetId, name, WI.TargetType.Page, connection);
 30 super(parentTarget, targetId, name, WI.TargetType.Page, connection, options);
3131
3232 const isPageContext = true;
3333 this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, isPageContext, null);

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, isProvisional} = {})
2929 {
3030 console.assert(parentTarget === null || parentTarget instanceof WI.Target);
 31 console.assert(!isPaused || parentTarget.hasCommand("Target.setPauseOnStart"));
3132 super();
3233
3334 this._parentTarget = parentTarget;

@@WI.Target = class Target extends WI.Object
3536 this._name = name;
3637 this._type = type;
3738 this._connection = connection;
 39 this._isPaused = !!isPaused;
 40 this._isProvisional = !!isProvisional;
3841 this._executionContext = null;
3942 this._mainResource = null;
4043 this._resourceCollection = new WI.ResourceCollection;

@@WI.Target = class Target extends WI.Object
9699 if (this.hasCommand("Inspector.initialized"))
97100 this.InspectorAgent.initialized();
98101 });
 102
 103 if (this._isPaused) {
 104 console.assert(this._parentTarget.hasCommand("Target.resume"));
 105 this._parentTarget.TargetAgent.resume(this._identifier, (error) => {
 106 if (error) {
 107 // Ignore errors if the target was destroyed after the command was sent.
 108 if (!this.isDestroyed)
 109 WI.reportInternalError(error);
 110 return;
 111 }
 112
 113 this._isPaused = false;
 114 });
 115 }
99116 }
100117
101118 activateExtraDomain(domainName)

@@WI.Target = class Target extends WI.Object
176193 get resourceCollection() { return this._resourceCollection; }
177194 get extraScriptCollection() { return this._extraScriptCollection; }
178195
 196 get isProvisional() { return this._isProvisional; }
 197 get isPaused() { return this._isPaused; }
179198 get isDestroyed() { return this._isDestroyed; }
180199
181200 get displayName() { return this._name; }

@@WI.Target = class Target extends WI.Object
215234 this.dispatchEventToListeners(WI.Target.Event.ScriptAdded, {script});
216235 }
217236
 237 didCommitProvisionalTarget()
 238 {
 239 console.assert(this._isProvisional);
 240 this._isProvisional = false;
 241 }
 242
218243 destroy()
219244 {
220245 this._isDestroyed = true;

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, options = {})
2929 {
30  super(parentTarget, workerId, name, WI.TargetType.Worker, connection);
 30 super(parentTarget, workerId, name, WI.TargetType.Worker, connection, options);
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::connect(Inspector::FrontendChannel::ConnectionType co
6969
7070void InspectorTargetProxy::disconnect()
7171{
 72 if (isPaused())
 73 setPaused(false);
 74
7275 if (m_provisionalPage) {
7376 m_provisionalPage->process().send(Messages::WebPage::DisconnectInspector(identifier()), m_provisionalPage->webPageID());
7477 return;

Source/WebKit/UIProcess/WebPageInspectorController.cpp

@@void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta
167167 m_targetAgent->sendMessageFromTargetToFrontend(targetId, message);
168168}
169169
 170bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const
 171{
 172 if (!m_frontendRouter->hasFrontends())
 173 return false;
 174
 175 auto* target = m_targets.get(getTargetID(provisionalPage));
 176 ASSERT(target);
 177 return target->isPaused();
 178}
 179
 180void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPageProxy& provisionalPage, WTF::Function<void()>&& callback)
 181{
 182 auto* target = m_targets.get(getTargetID(provisionalPage));
 183 ASSERT(target);
 184 target->setResumeCallback(WTFMove(callback));
 185}
 186
170187void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage)
171188{
172189 addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page));

Source/WebKit/UIProcess/WebPageInspectorController.h

@@public:
6666 void destroyInspectorTarget(const String& targetId);
6767 void sendMessageToInspectorFrontend(const String& targetId, const String& message);
6868
 69 bool shouldPauseLoading(const ProvisionalPageProxy&) const;
 70 void setContinueLoadingCallback(const ProvisionalPageProxy&, WTF::Function<void()>&&);
 71
6972 void didCreateProvisionalPage(ProvisionalPageProxy&);
7073 void willDestroyProvisionalPage(const ProvisionalPageProxy&);
7174 void didCommitProvisionalPage(WebCore::PageIdentifier oldWebPageID, WebCore::PageIdentifier newWebPageID);

Source/WebKit/UIProcess/WebPageProxy.cpp

@@void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, s
30973097
30983098 m_provisionalPage = makeUnique<ProvisionalPageProxy>(*this, newProcess.copyRef(), WTFMove(suspendedPage), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient);
30993099
3100  if (auto* item = navigation.targetItem()) {
3101  LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
 3100 auto continuation = [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), newProcess = WTFMove(newProcess), websitePolicies = WTFMove(websitePolicies)]() mutable {
 3101 if (auto* item = navigation->targetItem()) {
 3102 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
31023103
3103  auto transaction = m_pageLoadState.transaction();
3104  m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), item->url() });
 3104 auto transaction = m_pageLoadState.transaction();
 3105 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), item->url() });
31053106
3106  m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
3107  return;
3108  }
 3107 m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
 3108 return;
 3109 }
31093110
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  }
 3111 if (m_backForwardList->currentItem() && (navigation->lockBackForwardList() == LockBackForwardList::Yes || navigation->lockHistory() == LockHistory::Yes)) {
 3112 // 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
 3113 // it instead of creating a new one.
 3114 newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_provisionalPage->webPageID());
 3115 }
31153116
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));
 3117 // FIXME: Work out timing of responding with the last policy delegate, etc
 3118 ASSERT(!navigation->currentRequest().isEmpty());
 3119 if (auto& substituteData = navigation->substituteData())
 3120 m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies));
 3121 else
 3122 m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
 3123 };
 3124 if (m_inspectorController->shouldPauseLoading(*m_provisionalPage))
 3125 m_inspectorController->setContinueLoadingCallback(*m_provisionalPage, WTFMove(continuation));
31203126 else
3121  m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
 3127 continuation();
31223128}
31233129
31243130bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const

Source/WebKit/WebProcess/WebPage/WebInspectorFrontendAPIDispatcher.cpp

@@void WebInspectorFrontendAPIDispatcher::dispatchMessageAsync(const String& messa
9292
9393void WebInspectorFrontendAPIDispatcher::evaluateOrQueueExpression(const String& expression)
9494{
 95 fprintf(stderr, "evaluateOrQueueExpression %s\n", expression.left(200).ascii().data());
9596 if (!m_frontendLoaded || m_suspended) {
9697 m_queue.append(expression);
9798 return;

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-12-03 youenn fablet <youenn@apple.com>
222
323 Add support for camera rotation when capturing in UIProcess

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 const url = "http://localhost:8000/inspector/target/provisional-load-cancels-previous-load.html";
 29 let navigatedTwice = false;
 30
 31 WI.targetManager.addEventListener(WI.TargetManager.Event.TargetAdded, (event) => {
 32 let target = event.data.target;
 33 let targetId = stableTargetId(target.identifier);
 34 InspectorTest.pass(`Should receive TargetAdded event for target ${targetId}.`);
 35 InspectorTest.expectTrue(target.isProvisional, `Target ${targetId} should be provisional.`);
 36 InspectorTest.expectTrue(target.isPaused, `Target ${targetId} should be paused on start.`);
 37 if (!navigatedTwice) {
 38 navigatedTwice = true;
 39
 40 // Send two consequtive navigation requests. The latter will cancel provisional
 41 // load of the former.
 42 WI.mainTarget.PageAgent.navigate(url);
 43 }
 44 });
 45
 46 WI.targetManager.addEventListener(WI.TargetManager.Event.DidCommitProvisionalTarget, (event) => {
 47 let {previousTargetId, target} = event.data;
 48 InspectorTest.pass(`Should receive DidCommitProvisionalTarget event ${stableTargetId(previousTargetId)} => ${stableTargetId(target.identifier)}.`);
 49 });
 50
 51 WI.targetManager.addEventListener(WI.TargetManager.Event.TargetRemoved, (event) =>{
 52 let targetId = stableTargetId(event.data.target.identifier);
 53 InspectorTest.pass(`Should receive TargetRemoved event for target ${targetId}`);
 54 });
 55
 56 // Wait for page reload event to avoid race between test results flushing and the test completion.
 57 InspectorTest.awaitEvent(FrontendTestHarness.Event.TestPageDidLoad)
 58 .then(() => {
 59 InspectorTest.expectEqual(lastAssignedId, 3, `Should have seen 3 different targets.`);
 60 })
 61 .then(resolve);
 62
 63 WI.mainTarget.PageAgent.navigate(url);
 64 }
 65 });
 66
 67 suite.runTestCasesAndFinish();
 68}
 69</script>
 70</head>
 71<body onload="runTest()">
 72<p>Test that two consequtive cross domain navigation requests will result in two
 73provisional targets being created, first of which is later destroyed and the second
 74is committed.</p>
 75</body>
 76</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);