constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) {
    const minMax = [Infinity, Infinity, -Infinity, -Infinity];

    // We round the coordinates to slightly reduce the number of edges in the
    // final outlines.
    const NUMBER_OF_DIGITS = 4;
    const EPSILON = 10 ** -NUMBER_OF_DIGITS;

    // The coordinates of the boxes are in the page coordinate system.
    for (const { x, y, width, height } of boxes) {
      const x1 = Math.floor((x - borderWidth) / EPSILON) * EPSILON;
      const x2 = Math.ceil((x + width + borderWidth) / EPSILON) * EPSILON;
      const y1 = Math.floor((y - borderWidth) / EPSILON) * EPSILON;
      const y2 = Math.ceil((y + height + borderWidth) / EPSILON) * EPSILON;
      const left = [x1, y1, y2, true];
      const right = [x2, y1, y2, false];
      this.#verticalEdges.push(left, right);

      Util.rectBoundingBox(x1, y1, x2, y2, minMax);
    }

    const bboxWidth = minMax[2] - minMax[0] + 2 * innerMargin;
    const bboxHeight = minMax[3] - minMax[1] + 2 * innerMargin;
    const shiftedMinX = minMax[0] - innerMargin;
    const shiftedMinY = minMax[1] - innerMargin;
    const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2);
    const lastPoint = [lastEdge[0], lastEdge[2]];

    // Convert the coordinates of the edges into box coordinates.
    for (const edge of this.#verticalEdges) {
      const [x, y1, y2] = edge;
      edge[0] = (x - shiftedMinX) / bboxWidth;
      edge[1] = (y1 - shiftedMinY) / bboxHeight;
      edge[2] = (y2 - shiftedMinY) / bboxHeight;
    }

    this.#box = new Float32Array([
      shiftedMinX,
      shiftedMinY,
      bboxWidth,
      bboxHeight,
    ]);
    this.#lastPoint = lastPoint;
  }
Construct an outliner.
@param {Array<Object>} boxes - An array of axis-aligned rectangles.
@param {number} borderWidth - The width of the border of the boxes, it
  allows to make the boxes bigger (or smaller).
@param {number} innerMargin - The margin between the boxes and the
  outlines. It's important to not have a null innerMargin when we want to
  draw the outline else the stroked outline could be clipped because of its
  width.
@param {boolean} isLTR - true if we're in LTR mode. It's used to determine
  the last point of the boxes.