getSourceTiles(pixelRatio, projection, tile) {
    if (tile.getState() === TileState.IDLE) {
      tile.setState(TileState.LOADING);
      const urlTileCoord = tile.wrappedTileCoord;
      const tileGrid = this.getTileGridForProjection(projection);
      const extent = tileGrid.getTileCoordExtent(urlTileCoord);
      const z = urlTileCoord[0];
      const resolution = tileGrid.getResolution(z);
      // make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
      bufferExtent(extent, -resolution, extent);
      const sourceTileGrid = this.tileGrid;
      const sourceExtent = sourceTileGrid.getExtent();
      if (sourceExtent) {
        getIntersection(extent, sourceExtent, extent);
      }
      const sourceZ = sourceTileGrid.getZForResolution(
        resolution,
        this.zDirection,
      );

      sourceTileGrid.forEachTileCoord(extent, sourceZ, (sourceTileCoord) => {
        const tileUrl = this.tileUrlFunction(
          sourceTileCoord,
          pixelRatio,
          projection,
        );
        if (!this.sourceTiles_[tileUrl]) {
          this.sourceTiles_[tileUrl] = new this.tileClass(
            sourceTileCoord,
            tileUrl ? TileState.IDLE : TileState.EMPTY,
            tileUrl,
            this.format_,
            this.tileLoadFunction,
          );
        }
        const sourceTile = this.sourceTiles_[tileUrl];
        tile.sourceTiles.push(sourceTile);
        if (!this.tileKeysBySourceTileUrl_[tileUrl]) {
          this.tileKeysBySourceTileUrl_[tileUrl] = [];
        }
        this.tileKeysBySourceTileUrl_[tileUrl].push(tile.getKey());
        const sourceTileState = sourceTile.getState();
        if (sourceTileState < TileState.LOADED) {
          const listenChange = (event) => {
            this.handleTileChange(event);
            const state = sourceTile.getState();
            if (state === TileState.LOADED || state === TileState.ERROR) {
              const sourceTileKey = sourceTile.getKey();
              if (sourceTileKey in tile.errorTileKeys) {
                if (sourceTile.getState() === TileState.LOADED) {
                  delete tile.errorTileKeys[sourceTileKey];
                }
              } else {
                tile.loadingSourceTiles--;
              }
              if (state === TileState.ERROR) {
                tile.errorTileKeys[sourceTileKey] = true;
              } else {
                sourceTile.removeEventListener(EventType.CHANGE, listenChange);
              }
              if (tile.loadingSourceTiles === 0) {
                tile.setState(
                  isEmpty(tile.errorTileKeys)
                    ? TileState.LOADED
                    : TileState.ERROR,
                );
              }
            }
          };
          sourceTile.addEventListener(EventType.CHANGE, listenChange);
          tile.loadingSourceTiles++;
        }
        if (sourceTileState === TileState.IDLE) {
          sourceTile.extent =
            sourceTileGrid.getTileCoordExtent(sourceTileCoord);
          sourceTile.projection = projection;
          sourceTile.resolution = sourceTileGrid.getResolution(
            sourceTileCoord[0],
          );
          sourceTile.load();
        }
      });
      if (!tile.loadingSourceTiles) {
        tile.setState(
          tile.sourceTiles.some(
            (sourceTile) => sourceTile.getState() === TileState.ERROR,
          )
            ? TileState.ERROR
            : TileState.LOADED,
        );
      }
    }

    return tile.sourceTiles;
  }
@param {number} pixelRatio Pixel ratio.
@param {import("../proj/Projection").default} projection Projection.
@param {VectorRenderTile} tile Vector render tile.
@return {Array<import("../VectorTile").default>} Tile keys.