tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ReftestFissionParent.sys.mjs (9288B)


      1 export class ReftestFissionParent extends JSWindowActorParent {
      2  tellChildrenToFlushRendering(
      3    browsingContext,
      4    ignoreThrottledAnimations,
      5    needsAnimationFrame
      6  ) {
      7    let promises = [];
      8    this.tellChildrenToFlushRenderingRecursive(
      9      browsingContext,
     10      ignoreThrottledAnimations,
     11      needsAnimationFrame,
     12      promises
     13    );
     14    return Promise.allSettled(promises);
     15  }
     16 
     17  tellChildrenToFlushRenderingRecursive(
     18    browsingContext,
     19    ignoreThrottledAnimations,
     20    needsAnimationFrame,
     21    promises
     22  ) {
     23    let cwg = browsingContext.currentWindowGlobal;
     24    if (cwg && cwg.isProcessRoot) {
     25      let a = cwg.getActor("ReftestFission");
     26      if (a) {
     27        let responsePromise = a.sendQuery("FlushRendering", {
     28          ignoreThrottledAnimations,
     29          needsAnimationFrame,
     30        });
     31        promises.push(responsePromise);
     32      }
     33    }
     34 
     35    for (let context of browsingContext.children) {
     36      this.tellChildrenToFlushRenderingRecursive(
     37        context,
     38        ignoreThrottledAnimations,
     39        needsAnimationFrame,
     40        promises
     41      );
     42    }
     43  }
     44 
     45  // not including browsingContext
     46  getNearestProcessRootProperDescendants(browsingContext) {
     47    let result = [];
     48    for (let context of browsingContext.children) {
     49      this.getNearestProcessRootProperDescendantsRecursive(context, result);
     50    }
     51    return result;
     52  }
     53 
     54  getNearestProcessRootProperDescendantsRecursive(browsingContext, result) {
     55    let cwg = browsingContext.currentWindowGlobal;
     56    if (cwg && cwg.isProcessRoot) {
     57      result.push(browsingContext);
     58      return;
     59    }
     60    for (let context of browsingContext.children) {
     61      this.getNearestProcessRootProperDescendantsRecursive(context, result);
     62    }
     63  }
     64 
     65  // tell children and itself
     66  async tellChildrenToUpdateLayerTree(browsingContext) {
     67    let errorStrings = [];
     68    let infoStrings = [];
     69 
     70    let cwg = browsingContext.currentWindowGlobal;
     71    if (!cwg || !cwg.isProcessRoot) {
     72      if (cwg) {
     73        errorStrings.push(
     74          "tellChildrenToUpdateLayerTree called on a non process root?"
     75        );
     76      }
     77      return { errorStrings, infoStrings };
     78    }
     79 
     80    let actor = cwg.getActor("ReftestFission");
     81    if (!actor) {
     82      return { errorStrings, infoStrings };
     83    }
     84 
     85    // When we paint a document we also update the EffectsInfo visible rect in
     86    // nsSubDocumentFrame for any remote subdocuments. This visible rect is
     87    // used to limit painting for the subdocument in the subdocument's process.
     88    // So we want to ensure that the IPC message that updates the visible rect
     89    // to the subdocument's process arrives before we paint the subdocument
     90    // (otherwise our painting might not be up to date). We do this by sending,
     91    // and waiting for reply, an "EmptyMessage" to every direct descendant that
     92    // is in another process. Since we send the "EmptyMessage" after the
     93    // visible rect update message we know that the visible rect will be
     94    // updated by the time we hear back from the "EmptyMessage". Then we can
     95    // ask the subdocument process to paint.
     96 
     97    try {
     98      let result = await actor.sendQuery("UpdateLayerTree");
     99      errorStrings.push(...result.errorStrings);
    100    } catch (e) {
    101      infoStrings.push(
    102        "tellChildrenToUpdateLayerTree UpdateLayerTree msg to child rejected: " +
    103          e
    104      );
    105    }
    106 
    107    let descendants =
    108      actor.getNearestProcessRootProperDescendants(browsingContext);
    109    for (let context of descendants) {
    110      let cwg2 = context.currentWindowGlobal;
    111      if (cwg2) {
    112        if (!cwg2.isProcessRoot) {
    113          errorStrings.push(
    114            "getNearestProcessRootProperDescendants returned a non process root?"
    115          );
    116        }
    117        let actor2 = cwg2.getActor("ReftestFission");
    118        if (actor2) {
    119          try {
    120            await actor2.sendQuery("EmptyMessage");
    121          } catch (e) {
    122            infoStrings.push(
    123              "tellChildrenToUpdateLayerTree EmptyMessage msg to child rejected: " +
    124                e
    125            );
    126          }
    127 
    128          try {
    129            let result2 = await actor2.tellChildrenToUpdateLayerTree(context);
    130            errorStrings.push(...result2.errorStrings);
    131            infoStrings.push(...result2.infoStrings);
    132          } catch (e) {
    133            errorStrings.push(
    134              "tellChildrenToUpdateLayerTree recursive tellChildrenToUpdateLayerTree call rejected: " +
    135                e
    136            );
    137          }
    138        }
    139      }
    140    }
    141 
    142    return { errorStrings, infoStrings };
    143  }
    144 
    145  tellChildrenToSetupDisplayport(browsingContext, promises) {
    146    let cwg = browsingContext.currentWindowGlobal;
    147    if (cwg && cwg.isProcessRoot) {
    148      let a = cwg.getActor("ReftestFission");
    149      if (a) {
    150        let responsePromise = a.sendQuery("SetupDisplayport");
    151        promises.push(responsePromise);
    152      }
    153    }
    154 
    155    for (let context of browsingContext.children) {
    156      this.tellChildrenToSetupDisplayport(context, promises);
    157    }
    158  }
    159 
    160  tellChildrenToSetupAsyncScrollOffsets(
    161    browsingContext,
    162    allowFailure,
    163    promises
    164  ) {
    165    let cwg = browsingContext.currentWindowGlobal;
    166    if (cwg && cwg.isProcessRoot) {
    167      let a = cwg.getActor("ReftestFission");
    168      if (a) {
    169        let responsePromise = a.sendQuery("SetupAsyncScrollOffsets", {
    170          allowFailure,
    171        });
    172        promises.push(responsePromise);
    173      }
    174    }
    175 
    176    for (let context of browsingContext.children) {
    177      this.tellChildrenToSetupAsyncScrollOffsets(
    178        context,
    179        allowFailure,
    180        promises
    181      );
    182    }
    183  }
    184 
    185  receiveMessage(msg) {
    186    switch (msg.name) {
    187      case "ForwardAfterPaintEvent": {
    188        let cwg = msg.data.toBrowsingContext.currentWindowGlobal;
    189        if (cwg) {
    190          let a = cwg.getActor("ReftestFission");
    191          if (a) {
    192            a.sendAsyncMessage(
    193              "ForwardAfterPaintEventToSelfAndParent",
    194              msg.data
    195            );
    196          }
    197        }
    198        break;
    199      }
    200      case "FlushRendering": {
    201        let promise = this.tellChildrenToFlushRendering(
    202          msg.data.browsingContext,
    203          msg.data.ignoreThrottledAnimations,
    204          msg.data.needsAnimationFrame
    205        );
    206        return promise.then(function (results) {
    207          let errorStrings = [];
    208          let warningStrings = [];
    209          let infoStrings = [];
    210          for (let r of results) {
    211            if (r.status != "fulfilled") {
    212              if (r.status == "pending") {
    213                errorStrings.push(
    214                  "FlushRendering sendQuery to child promise still pending?"
    215                );
    216              } else {
    217                // We expect actors to go away causing sendQuery's to fail, so
    218                // just note it.
    219                infoStrings.push(
    220                  "FlushRendering sendQuery to child promise rejected: " +
    221                    r.reason
    222                );
    223              }
    224              continue;
    225            }
    226 
    227            errorStrings.push(...r.value.errorStrings);
    228            warningStrings.push(...r.value.warningStrings);
    229            infoStrings.push(...r.value.infoStrings);
    230          }
    231          return { errorStrings, warningStrings, infoStrings };
    232        });
    233      }
    234      case "UpdateLayerTree": {
    235        return this.tellChildrenToUpdateLayerTree(msg.data.browsingContext);
    236      }
    237      case "TellChildrenToSetupDisplayport": {
    238        let promises = [];
    239        this.tellChildrenToSetupDisplayport(msg.data.browsingContext, promises);
    240        return Promise.allSettled(promises).then(function (results) {
    241          let errorStrings = [];
    242          let infoStrings = [];
    243          for (let r of results) {
    244            if (r.status != "fulfilled") {
    245              // We expect actors to go away causing sendQuery's to fail, so
    246              // just note it.
    247              infoStrings.push(
    248                "SetupDisplayport sendQuery to child promise rejected: " +
    249                  r.reason
    250              );
    251              continue;
    252            }
    253 
    254            errorStrings.push(...r.value.errorStrings);
    255            infoStrings.push(...r.value.infoStrings);
    256          }
    257          return { errorStrings, infoStrings };
    258        });
    259      }
    260 
    261      case "SetupAsyncScrollOffsets": {
    262        let promises = [];
    263        this.tellChildrenToSetupAsyncScrollOffsets(
    264          this.manager.browsingContext,
    265          msg.data.allowFailure,
    266          promises
    267        );
    268        return Promise.allSettled(promises).then(function (results) {
    269          let errorStrings = [];
    270          let infoStrings = [];
    271          let updatedAny = false;
    272          for (let r of results) {
    273            if (r.status != "fulfilled") {
    274              // We expect actors to go away causing sendQuery's to fail, so
    275              // just note it.
    276              infoStrings.push(
    277                "SetupAsyncScrollOffsets sendQuery to child promise rejected: " +
    278                  r.reason
    279              );
    280              continue;
    281            }
    282 
    283            errorStrings.push(...r.value.errorStrings);
    284            infoStrings.push(...r.value.infoStrings);
    285            if (r.value.updatedAny) {
    286              updatedAny = true;
    287            }
    288          }
    289          return { errorStrings, infoStrings, updatedAny };
    290        });
    291      }
    292    }
    293    return undefined;
    294  }
    295 }