Repository: mozilla/pdf.js
File: web/struct_tree_layer_builder.js (JavaScript)

Code before:
    if (!id) {
      return false;
    }

    // We cannot add the created element to the text layer immediately, as the
    // text layer might not be ready yet. Instead, we store the element and add
    // it later in `addElementsToTextLayer`.

    element.setAttribute("aria-owns", id);
    const img = document.createElement("span");
    (this.#elementsToAddToTextLayer ||= new Map()).set(id, img);
    img.setAttribute("role", "img");
    img.setAttribute("aria-label", removeNullCharacters(alt));

    const { pageHeight, pageX, pageY } = this.#rawDims;
    const calc = "calc(var(--total-scale-factor) *";
    const { style } = img;
    style.width = `${calc}${bbox[2] - bbox[0]}px)`;
    style.height = `${calc}${bbox[3] - bbox[1]}px)`;
    style.left = `${calc}${bbox[0] - pageX}px)`;
    style.top = `${calc}${pageHeight - bbox[3] + pageY}px)`;

    return true;
  }

  addElementsToTextLayer() {
    if (this.#elementsToAddToTextLayer) {
      for (const [id, img] of this.#elementsToAddToTextLayer) {
        document.getElementById(id)?.append(img);
      }
      this.#elementsToAddToTextLayer.clear();
      this.#elementsToAddToTextLayer = null;
    }
    if (this.#elementsToHideInTextLayer) {
      for (const id of this.#elementsToHideInTextLayer) {
        const elem = document.getElementById(id);
        if (elem) {
          elem.ariaHidden = true;
        }
      }
      this.#elementsToHideInTextLayer = null;
    }
    if (this.#elementsToStealFromTextLayer) {
      for (const [[element, ids]] of this.#elementsToStealFromTextLayer) {
        let textContent = "";
        for (const id of ids) {
          const elem = document.getElementById(id);
          if (elem) {
            textContent += elem.textContent.trim() || "";
            // Aria-hide the element in order to avoid duplicate reading of the
            // math content by screen readers.

Review comment (suggestion):
Maybe we should call this `updateTextLayer` or something similar because it does more than just adding elements now.

Code after:
    if (!id) {
      return false;
    }

    // We cannot add the created element to the text layer immediately, as the
    // text layer might not be ready yet. Instead, we store the element and add
    // it later in `addElementsToTextLayer`.

    element.setAttribute("aria-owns", id);
    const img = document.createElement("span");
    (this.#elementsToAddToTextLayer ||= new Map()).set(id, img);
    img.setAttribute("role", "img");
    img.setAttribute("aria-label", removeNullCharacters(alt));

    const { pageHeight, pageX, pageY } = this.#rawDims;
    const calc = "calc(var(--total-scale-factor) *";
    const { style } = img;
    style.width = `${calc}${bbox[2] - bbox[0]}px)`;
    style.height = `${calc}${bbox[3] - bbox[1]}px)`;
    style.left = `${calc}${bbox[0] - pageX}px)`;
    style.top = `${calc}${pageHeight - bbox[3] + pageY}px)`;

    return true;
  }

  updateTextLayer() {
    if (this.#elementsToAddToTextLayer) {
      for (const [id, img] of this.#elementsToAddToTextLayer) {
        document.getElementById(id)?.append(img);
      }
      this.#elementsToAddToTextLayer.clear();
      this.#elementsToAddToTextLayer = null;
    }
    if (this.#elementsToHideInTextLayer) {
      for (const id of this.#elementsToHideInTextLayer) {
        const elem = document.getElementById(id);
        if (elem) {
          elem.ariaHidden = true;
        }
      }
      this.#elementsToHideInTextLayer.length = 0;
      this.#elementsToHideInTextLayer = null;
    }
    if (this.#elementsToStealFromTextLayer) {
      for (
        let i = 0, ii = this.#elementsToStealFromTextLayer.length;
        i < ii;
        i += 2
      ) {
        const element = this.#elementsToStealFromTextLayer[i];
        const ids = this.#elementsToStealFromTextLayer[i + 1];