gecko-dev/gfx/layers/apz/test/apz_test_utils.js

119 строки
4.0 KiB
JavaScript

// Utilities for writing APZ tests using the framework added in bug 961289
// ----------------------------------------------------------------------
// Functions that convert the APZ test data into a more usable form.
// Every place we have a WebIDL sequence whose elements are dictionaries
// with two elements, a key, and a value, we convert this into a JS
// object with a property for each key/value pair. (This is the structure
// we really want, but we can't express in directly in WebIDL.)
// ----------------------------------------------------------------------
function convertEntries(entries) {
var result = {};
for (var i = 0; i < entries.length; ++i) {
result[entries[i].key] = entries[i].value;
}
return result;
}
function convertScrollFrameData(scrollFrames) {
var result = {};
for (var i = 0; i < scrollFrames.length; ++i) {
result[scrollFrames[i].scrollId] = convertEntries(scrollFrames[i].entries);
}
return result;
}
function convertBuckets(buckets) {
var result = {};
for (var i = 0; i < buckets.length; ++i) {
result[buckets[i].sequenceNumber] = convertScrollFrameData(buckets[i].scrollFrames);
}
return result;
}
function convertTestData(testData) {
var result = {};
result.paints = convertBuckets(testData.paints);
result.repaintRequests = convertBuckets(testData.repaintRequests);
return result;
}
// ----------------------------------------------------------------
// Utilities for reconstructing the structure of the APZC tree from
// 'parentScrollId' entries in the APZ test data.
// ----------------------------------------------------------------
// Create a node with scroll id 'id' in the APZC tree.
function makeNode(id) {
return {scrollId: id, children: []};
}
// Find a node with scroll id 'id' in the APZC tree rooted at 'root'.
function findNode(root, id) {
if (root.scrollId == id) {
return root;
}
for (var i = 0; i < root.children.length; ++i) {
var subtreeResult = findNode(root.children[i], id);
if (subtreeResult != null) {
return subtreeResult;
}
}
return null;
}
// Add a child -> parent link to the APZC tree rooted at 'root'.
function addLink(root, child, parent) {
var parentNode = findNode(root, parent);
if (parentNode == null) {
parentNode = makeNode(parent);
root.children.push(parentNode);
}
parentNode.children.push(makeNode(child));
}
// Add a root node to the APZC tree. It will become a direct
// child of 'root'.
function addRoot(root, id) {
root.children.push(makeNode(id));
}
// Given APZ test data for a single paint on the compositor side,
// reconstruct the APZC tree structure from the 'parentScrollId'
// entries that were logged. More specifically, the subset of the
// APZC tree structure corresponding to the layer subtree for the
// content process that triggered the paint, is reconstructed (as
// the APZ test data only contains information abot this subtree).
function buildApzcTree(paint) {
// The APZC tree can potentially have multiple root nodes,
// so we invent a node that is the parent of all roots.
// This 'root' does not correspond to an APZC.
var root = makeNode(-1);
for (var scrollId in paint) {
if ("hasNoParentWithSameLayersId" in paint[scrollId]) {
addRoot(root, scrollId);
} else if ("parentScrollId" in paint[scrollId]) {
addLink(root, scrollId, paint[scrollId]["parentScrollId"]);
}
}
return root;
}
function flushApzRepaints(aCallback, aWindow = window) {
if (!aCallback) {
throw "A callback must be provided!";
}
var repaintDone = function() {
SpecialPowers.Services.obs.removeObserver(repaintDone, "apz-repaints-flushed", false);
setTimeout(aCallback, 0);
};
SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed", false);
if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) {
dump("Flushed APZ repaints, waiting for callback...\n");
} else {
dump("Flushing APZ repaints was a no-op, triggering callback directly...\n");
repaintDone();
}
}