execute(
    targetContext,
    scaledCanvasSize,
    transform,
    viewRotation,
    snapToPixel,
    builderTypes,
    declutterTree,
  ) {
    const zs = Object.keys(this.executorsByZIndex_).map(Number);
    zs.sort(declutterTree ? descending : ascending);

    builderTypes = builderTypes ? builderTypes : ALL;
    const maxBuilderTypes = ALL.length;
    for (let i = 0, ii = zs.length; i < ii; ++i) {
      const zIndexKey = zs[i].toString();
      const replays = this.executorsByZIndex_[zIndexKey];
      for (let j = 0, jj = builderTypes.length; j < jj; ++j) {
        const builderType = builderTypes[j];
        const replay = replays[builderType];
        if (replay !== undefined) {
          const zIndexContext =
            declutterTree === null ? undefined : replay.getZIndexContext();
          const context = zIndexContext
            ? zIndexContext.getContext()
            : targetContext;
          const requireClip =
            this.maxExtent_ &&
            builderType !== 'Image' &&
            builderType !== 'Text';
          if (requireClip) {
            context.save();
            // setup clipping so that the parts of over-simplified geometries are not
            // visible outside the current extent when panning
            this.clip(context, transform);
          }
          if (
            !zIndexContext ||
            builderType === 'Text' ||
            builderType === 'Image'
          ) {
            replay.execute(
              context,
              scaledCanvasSize,
              transform,
              viewRotation,
              snapToPixel,
              declutterTree,
            );
          } else {
            zIndexContext.pushFunction((context) =>
              replay.execute(
                context,
                scaledCanvasSize,
                transform,
                viewRotation,
                snapToPixel,
                declutterTree,
              ),
            );
          }
          if (requireClip) {
            context.restore();
          }
          if (zIndexContext) {
            zIndexContext.offset();
            const index = zs[i] * maxBuilderTypes + ALL.indexOf(builderType);
            if (!this.deferredZIndexContexts_[index]) {
              this.deferredZIndexContexts_[index] = [];
            }
            this.deferredZIndexContexts_[index].push(zIndexContext);
          }
        }
      }
    }

    this.renderedContext_ = targetContext;
  }
@param {CanvasRenderingContext2D} targetContext Context.
@param {import('../../size.js').Size} scaledCanvasSize Scale of the context.
@param {import("../../transform.js").Transform} transform Transform.
@param {number} viewRotation View rotation.
@param {boolean} snapToPixel Snap point symbols and test to integer pixel.
@param {Array<import("../canvas.js").BuilderType>} [builderTypes] Ordered replay types to replay.
    Default is {@link module:ol/render/replay~ALL}
@param {import("rbush").default<import('./Executor.js').DeclutterEntry>|null} [declutterTree] Declutter tree.
    When set to null, no decluttering is done, even when the executor group has a `ZIndexContext`.