mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 04:09:50 +00:00
Bug 1716284 - [devtools] Add a reflow resource. r=ochameau.
This is meant to replace usage of the ReflowActor. Differential Revision: https://phabricator.services.mozilla.com/D117899
This commit is contained in:
parent
bf9d68cfb7
commit
a2652bf4e9
@ -305,7 +305,7 @@ LayoutChangesObserver.prototype = {
|
||||
_startEventLoop: function() {
|
||||
// Avoid emitting events if the targetActor has been detached (may happen
|
||||
// during shutdown)
|
||||
if (!this.targetActor || !this.targetActor.attached) {
|
||||
if (!this.targetActor || this.targetActor.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ const TYPES = {
|
||||
NETWORK_EVENT: "network-event",
|
||||
STYLESHEET: "stylesheet",
|
||||
NETWORK_EVENT_STACKTRACE: "network-event-stacktrace",
|
||||
REFLOW: "reflow",
|
||||
SOURCE: "source",
|
||||
THREAD_STATE: "thread-state",
|
||||
SERVER_SENT_EVENT: "server-sent-event",
|
||||
@ -75,6 +76,9 @@ const FrameTargetResources = augmentResourceDictionary({
|
||||
[TYPES.NETWORK_EVENT_STACKTRACE]: {
|
||||
path: "devtools/server/actors/resources/network-events-stacktraces",
|
||||
},
|
||||
[TYPES.REFLOW]: {
|
||||
path: "devtools/server/actors/resources/reflow",
|
||||
},
|
||||
[TYPES.SOURCE]: {
|
||||
path: "devtools/server/actors/resources/sources",
|
||||
},
|
||||
|
@ -19,6 +19,7 @@ DevToolsModules(
|
||||
"network-events-stacktraces.js",
|
||||
"network-events.js",
|
||||
"platform-messages.js",
|
||||
"reflow.js",
|
||||
"server-sent-events.js",
|
||||
"sources.js",
|
||||
"storage-cache.js",
|
||||
|
63
devtools/server/actors/resources/reflow.js
Normal file
63
devtools/server/actors/resources/reflow.js
Normal file
@ -0,0 +1,63 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
TYPES: { REFLOW },
|
||||
} = require("devtools/server/actors/resources/index");
|
||||
const Targets = require("devtools/server/actors/targets/index");
|
||||
|
||||
const {
|
||||
getLayoutChangesObserver,
|
||||
releaseLayoutChangesObserver,
|
||||
} = require("devtools/server/actors/reflow");
|
||||
|
||||
class ReflowWatcher {
|
||||
/**
|
||||
* Start watching for reflows related to a given Target Actor.
|
||||
*
|
||||
* @param TargetActor targetActor
|
||||
* The target actor from which we should observe reflows
|
||||
* @param Object options
|
||||
* Dictionary object with following attributes:
|
||||
* - onAvailable: mandatory function
|
||||
* This will be called for each resource.
|
||||
*/
|
||||
async watch(targetActor, { onAvailable }) {
|
||||
// Only track reflow for non-ParentProcess FRAME targets
|
||||
if (
|
||||
targetActor.targetType !== Targets.TYPES.FRAME ||
|
||||
targetActor.typeName === "parentProcessTarget"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._targetActor = targetActor;
|
||||
|
||||
const onReflows = reflows => {
|
||||
onAvailable([
|
||||
{
|
||||
resourceType: REFLOW,
|
||||
reflows,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
this._observer = getLayoutChangesObserver(targetActor);
|
||||
this._offReflows = this._observer.on("reflows", onReflows);
|
||||
this._observer.start();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
releaseLayoutChangesObserver(this._targetActor);
|
||||
|
||||
if (this._offReflows) {
|
||||
this._offReflows();
|
||||
this._offReflows = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReflowWatcher;
|
@ -156,6 +156,7 @@ exports.WatcherActor = protocol.ActorClassWithSpec(watcherSpec, {
|
||||
[Resources.TYPES.PLATFORM_MESSAGE]: true,
|
||||
[Resources.TYPES.NETWORK_EVENT]: hasBrowserElement,
|
||||
[Resources.TYPES.NETWORK_EVENT_STACKTRACE]: hasBrowserElement,
|
||||
[Resources.TYPES.REFLOW]: true,
|
||||
[Resources.TYPES.STYLESHEET]: hasBrowserElement,
|
||||
[Resources.TYPES.SOURCE]: hasBrowserElement,
|
||||
[Resources.TYPES.THREAD_STATE]: hasBrowserElement,
|
||||
|
@ -35,6 +35,10 @@ class MockTargetActor extends EventEmitter {
|
||||
get chromeEventHandler() {
|
||||
return this.docShell.chromeEventHandler;
|
||||
}
|
||||
|
||||
isDestroyed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function MockWindow(docShell) {
|
||||
|
@ -16,6 +16,7 @@ DevToolsModules(
|
||||
"network-event-stacktraces.js",
|
||||
"network-events.js",
|
||||
"platform-messages.js",
|
||||
"reflow.js",
|
||||
"root-node.js",
|
||||
"server-sent-events.js",
|
||||
"session-storage.js",
|
||||
|
20
devtools/shared/commands/resource/legacy-listeners/reflow.js
Normal file
20
devtools/shared/commands/resource/legacy-listeners/reflow.js
Normal file
@ -0,0 +1,20 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const ResourceCommand = require("devtools/shared/commands/resource/resource-command");
|
||||
|
||||
module.exports = async function({ targetFront, onAvailable }) {
|
||||
const reflowFront = await targetFront.getFront("reflow");
|
||||
reflowFront.on("reflows", reflows =>
|
||||
onAvailable([
|
||||
{
|
||||
resourceType: ResourceCommand.TYPES.REFLOW,
|
||||
reflows,
|
||||
},
|
||||
])
|
||||
);
|
||||
await reflowFront.start();
|
||||
};
|
@ -1033,6 +1033,7 @@ ResourceCommand.TYPES = ResourceCommand.prototype.TYPES = {
|
||||
EXTENSION_STORAGE: "extension-storage",
|
||||
INDEXED_DB: "indexed-db",
|
||||
NETWORK_EVENT_STACKTRACE: "network-event-stacktrace",
|
||||
REFLOW: "reflow",
|
||||
SOURCE: "source",
|
||||
THREAD_STATE: "thread-state",
|
||||
SERVER_SENT_EVENT: "server-sent-event",
|
||||
@ -1100,6 +1101,8 @@ const LegacyListeners = {
|
||||
.THREAD_STATE]: require("devtools/shared/commands/resource/legacy-listeners/thread-states"),
|
||||
[ResourceCommand.TYPES
|
||||
.SERVER_SENT_EVENT]: require("devtools/shared/commands/resource/legacy-listeners/server-sent-events"),
|
||||
[ResourceCommand.TYPES
|
||||
.REFLOW]: require("devtools/shared/commands/resource/legacy-listeners/reflow"),
|
||||
};
|
||||
|
||||
// Optional transformers for each type of resource.
|
||||
|
@ -43,6 +43,7 @@ support-files =
|
||||
[browser_resources_network_event_stacktraces.js]
|
||||
[browser_resources_network_events.js]
|
||||
[browser_resources_platform_messages.js]
|
||||
[browser_resources_reflows.js]
|
||||
[browser_resources_root_node.js]
|
||||
[browser_resources_server_sent_events.js]
|
||||
[browser_resources_several_resources.js]
|
||||
|
@ -0,0 +1,109 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test the ResourceCommand API for reflows
|
||||
|
||||
const { TYPES } = require("devtools/shared/commands/resource/resource-command");
|
||||
|
||||
add_task(async function() {
|
||||
const tab = await addTab(
|
||||
"http://example.com/document-builder.sjs?html=<h1>Test reflow resources</h1>"
|
||||
);
|
||||
|
||||
const { client, resourceCommand, targetCommand } = await initResourceCommand(
|
||||
tab
|
||||
);
|
||||
|
||||
const resources = [];
|
||||
const onAvailable = _resources => {
|
||||
resources.push(..._resources);
|
||||
};
|
||||
await resourceCommand.watchResources([TYPES.REFLOW], {
|
||||
onAvailable,
|
||||
});
|
||||
|
||||
is(resources.length, 0, "No reflow resource were sent initially");
|
||||
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
|
||||
const el = content.document.createElement("div");
|
||||
el.textContent = "1";
|
||||
content.document.body.appendChild(el);
|
||||
});
|
||||
|
||||
await waitFor(() => resources.length === 1);
|
||||
checkReflowResource(resources[0]);
|
||||
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
|
||||
const el = content.document.querySelector("div");
|
||||
el.style.display = "inline-grid";
|
||||
});
|
||||
|
||||
await waitFor(() => resources.length === 2);
|
||||
ok(
|
||||
true,
|
||||
"A reflow resource is sent when the display property of an element is modified"
|
||||
);
|
||||
checkReflowResource(resources.at(-1));
|
||||
|
||||
info("Check that adding an iframe does emit a reflow");
|
||||
const iframeBC = await SpecialPowers.spawn(
|
||||
tab.linkedBrowser,
|
||||
[],
|
||||
async () => {
|
||||
const el = content.document.createElement("iframe");
|
||||
const onIframeLoaded = new Promise(resolve =>
|
||||
el.addEventListener("load", resolve, { once: true })
|
||||
);
|
||||
content.document.body.appendChild(el);
|
||||
el.src =
|
||||
"http://example.org/document-builder.sjs?html=<h2>remote iframe</h2>";
|
||||
await onIframeLoaded;
|
||||
return el.browsingContext;
|
||||
}
|
||||
);
|
||||
|
||||
await waitFor(() => resources.length === 3);
|
||||
ok(true, "A reflow resource was received when adding a remote iframe");
|
||||
checkReflowResource(resources.at(-1));
|
||||
|
||||
info("Check that we receive reflow resources for the remote iframe");
|
||||
await SpecialPowers.spawn(iframeBC, [], () => {
|
||||
const el = content.document.createElement("section");
|
||||
el.textContent = "remote org iframe";
|
||||
el.style.display = "grid";
|
||||
content.document.body.appendChild(el);
|
||||
});
|
||||
|
||||
await waitFor(() => resources.length === 4);
|
||||
if (isFissionEnabled()) {
|
||||
ok(
|
||||
resources.at(-1).targetFront.url.includes("example.org"),
|
||||
"The reflow resource is linked to the remote target"
|
||||
);
|
||||
}
|
||||
checkReflowResource(resources.at(-1));
|
||||
|
||||
targetCommand.destroy();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
function checkReflowResource(resource) {
|
||||
is(
|
||||
resource.resourceType,
|
||||
TYPES.REFLOW,
|
||||
"The resource has the expected resourceType"
|
||||
);
|
||||
|
||||
ok(Array.isArray(resource.reflows), "the `reflows` property is an array");
|
||||
for (const reflow of resource.reflows) {
|
||||
is(
|
||||
Number.isFinite(reflow.start),
|
||||
true,
|
||||
"reflow start property is a number"
|
||||
);
|
||||
is(Number.isFinite(reflow.end), true, "reflow end property is a number");
|
||||
ok(reflow.end >= reflow.start, "end is greater than start");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user