"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const browser = require("../../../base/browser/browser.js");
const event = require("../../../base/common/event.js");
const lifecycle = require("../../../base/common/lifecycle.js");
const charWidthReader = require("./charWidthReader.js");
const editorOptions = require("../../common/config/editorOptions.js");
const fontInfo = require("../../common/config/fontInfo.js");
class FontMeasurementsImpl extends lifecycle.Disposable {
  constructor() {
    super();
    this._onDidChange = this._register(new event.Emitter());
    this.onDidChange = this._onDidChange.event;
    this._cache = new FontMeasurementsCache();
    this._evictUntrustedReadingsTimeout = -1;
  }
  dispose() {
    if (this._evictUntrustedReadingsTimeout !== -1) {
      window.clearTimeout(this._evictUntrustedReadingsTimeout);
      this._evictUntrustedReadingsTimeout = -1;
    }
    super.dispose();
  }
  /**
   * Clear all cached font information and trigger a change event.
   */
  clearAllFontInfos() {
    this._cache = new FontMeasurementsCache();
    this._onDidChange.fire();
  }
  _writeToCache(item, value) {
    this._cache.put(item, value);
    if (!value.isTrusted && this._evictUntrustedReadingsTimeout === -1) {
      this._evictUntrustedReadingsTimeout = window.setTimeout(() => {
        this._evictUntrustedReadingsTimeout = -1;
        this._evictUntrustedReadings();
      }, 5e3);
    }
  }
  _evictUntrustedReadings() {
    const values = this._cache.getValues();
    let somethingRemoved = false;
    for (const item of values) {
      if (!item.isTrusted) {
        somethingRemoved = true;
        this._cache.remove(item);
      }
    }
    if (somethingRemoved) {
      this._onDidChange.fire();
    }
  }
  /**
   * Read font information.
   */
  readFontInfo(bareFontInfo) {
    if (!this._cache.has(bareFontInfo)) {
      let readConfig = this._actualReadFontInfo(bareFontInfo);
      if (readConfig.typicalHalfwidthCharacterWidth <= 2 || readConfig.typicalFullwidthCharacterWidth <= 2 || readConfig.spaceWidth <= 2 || readConfig.maxDigitWidth <= 2) {
        readConfig = new fontInfo.FontInfo({
          pixelRatio: browser.PixelRatio.value,
          fontFamily: readConfig.fontFamily,
          fontWeight: readConfig.fontWeight,
          fontSize: readConfig.fontSize,
          fontFeatureSettings: readConfig.fontFeatureSettings,
          lineHeight: readConfig.lineHeight,
          letterSpacing: readConfig.letterSpacing,
          isMonospace: readConfig.isMonospace,
          typicalHalfwidthCharacterWidth: Math.max(readConfig.typicalHalfwidthCharacterWidth, 5),
          typicalFullwidthCharacterWidth: Math.max(readConfig.typicalFullwidthCharacterWidth, 5),
          canUseHalfwidthRightwardsArrow: readConfig.canUseHalfwidthRightwardsArrow,
          spaceWidth: Math.max(readConfig.spaceWidth, 5),
          middotWidth: Math.max(readConfig.middotWidth, 5),
          wsmiddotWidth: Math.max(readConfig.wsmiddotWidth, 5),
          maxDigitWidth: Math.max(readConfig.maxDigitWidth, 5)
        }, false);
      }
      this._writeToCache(bareFontInfo, readConfig);
    }
    return this._cache.get(bareFontInfo);
  }
  _createRequest(chr, type, all, monospace) {
    const result = new charWidthReader.CharWidthRequest(chr, type);
    all.push(result);
    if (monospace) {
      monospace.push(result);
    }
    return result;
  }
  _actualReadFontInfo(bareFontInfo) {
    const all = [];
    const monospace = [];
    const typicalHalfwidthCharacter = this._createRequest("n", 0, all, monospace);
    const typicalFullwidthCharacter = this._createRequest("ｍ", 0, all, null);
    const space = this._createRequest(" ", 0, all, monospace);
    const digit0 = this._createRequest("0", 0, all, monospace);
    const digit1 = this._createRequest("1", 0, all, monospace);
    const digit2 = this._createRequest("2", 0, all, monospace);
    const digit3 = this._createRequest("3", 0, all, monospace);
    const digit4 = this._createRequest("4", 0, all, monospace);
    const digit5 = this._createRequest("5", 0, all, monospace);
    const digit6 = this._createRequest("6", 0, all, monospace);
    const digit7 = this._createRequest("7", 0, all, monospace);
    const digit8 = this._createRequest("8", 0, all, monospace);
    const digit9 = this._createRequest("9", 0, all, monospace);
    const rightwardsArrow = this._createRequest("→", 0, all, monospace);
    const halfwidthRightwardsArrow = this._createRequest("￫", 0, all, null);
    const middot = this._createRequest("·", 0, all, monospace);
    const wsmiddotWidth = this._createRequest(String.fromCharCode(11825), 0, all, null);
    const monospaceTestChars = "|/-_ilm%";
    for (let i = 0, len = monospaceTestChars.length; i < len; i++) {
      this._createRequest(monospaceTestChars.charAt(i), 0, all, monospace);
      this._createRequest(monospaceTestChars.charAt(i), 1, all, monospace);
      this._createRequest(monospaceTestChars.charAt(i), 2, all, monospace);
    }
    charWidthReader.readCharWidths(bareFontInfo, all);
    const maxDigitWidth = Math.max(digit0.width, digit1.width, digit2.width, digit3.width, digit4.width, digit5.width, digit6.width, digit7.width, digit8.width, digit9.width);
    let isMonospace = bareFontInfo.fontFeatureSettings === editorOptions.EditorFontLigatures.OFF;
    const referenceWidth = monospace[0].width;
    for (let i = 1, len = monospace.length; isMonospace && i < len; i++) {
      const diff = referenceWidth - monospace[i].width;
      if (diff < -1e-3 || diff > 1e-3) {
        isMonospace = false;
        break;
      }
    }
    let canUseHalfwidthRightwardsArrow = true;
    if (isMonospace && halfwidthRightwardsArrow.width !== referenceWidth) {
      canUseHalfwidthRightwardsArrow = false;
    }
    if (halfwidthRightwardsArrow.width > rightwardsArrow.width) {
      canUseHalfwidthRightwardsArrow = false;
    }
    return new fontInfo.FontInfo({
      pixelRatio: browser.PixelRatio.value,
      fontFamily: bareFontInfo.fontFamily,
      fontWeight: bareFontInfo.fontWeight,
      fontSize: bareFontInfo.fontSize,
      fontFeatureSettings: bareFontInfo.fontFeatureSettings,
      lineHeight: bareFontInfo.lineHeight,
      letterSpacing: bareFontInfo.letterSpacing,
      isMonospace,
      typicalHalfwidthCharacterWidth: typicalHalfwidthCharacter.width,
      typicalFullwidthCharacterWidth: typicalFullwidthCharacter.width,
      canUseHalfwidthRightwardsArrow,
      spaceWidth: space.width,
      middotWidth: middot.width,
      wsmiddotWidth: wsmiddotWidth.width,
      maxDigitWidth
    }, true);
  }
}
class FontMeasurementsCache {
  constructor() {
    this._keys = /* @__PURE__ */ Object.create(null);
    this._values = /* @__PURE__ */ Object.create(null);
  }
  has(item) {
    const itemId = item.getId();
    return !!this._values[itemId];
  }
  get(item) {
    const itemId = item.getId();
    return this._values[itemId];
  }
  put(item, value) {
    const itemId = item.getId();
    this._keys[itemId] = item;
    this._values[itemId] = value;
  }
  remove(item) {
    const itemId = item.getId();
    delete this._keys[itemId];
    delete this._values[itemId];
  }
  getValues() {
    return Object.keys(this._keys).map((id) => this._values[id]);
  }
}
const FontMeasurements = new FontMeasurementsImpl();
exports.FontMeasurements = FontMeasurements;
