Обнаружение пропущенных символьных глифов и маленьких квадратиков Firefox с шестнадцатеричными кодовыми точками внутри них - PullRequest
0 голосов
/ 09 марта 2020

Я хочу иметь возможность проверить, правильно ли будет отображаться заданный символ c, такой как ? (это смайлик с каплями дождя, если вы его не видите), в веб-браузере пользователя, чтобы если этот символ не отображается, я могу использовать альтернативу.

Следующий код делает трюк в Chrome:

export function doesCharacterGlyphExist(elementOrFont: Element | string, charOrCodePoint: string | number): boolean {
  if (typeof charOrCodePoint === 'number')
    charOrCodePoint = String.fromCodePoint(charOrCodePoint);

  const metrics = getFontMetrics(elementOrFont);
  const PADDING = 8;
  const size = metrics.lineHeight + PADDING;

  const canvas0 = (doesCharacterGlyphExist as any).canvas0 || ((doesCharacterGlyphExist as any).canvas0 =
                  document.createElement('canvas') as HTMLCanvasElement);
  const canvas1 = (doesCharacterGlyphExist as any).canvas1 || ((doesCharacterGlyphExist as any).canvas1 =
                  document.createElement('canvas') as HTMLCanvasElement);
  const canvases = [canvas0, canvas1];
  const pixmaps = [];

  for (let i = 0; i < 2; ++i) {
    const canvas = canvases[i];

    canvas.width = size;
    canvas.height = size;
    canvas.style.opacity = '1';

    const context = canvas.getContext('2d');

    context.fillStyle = 'white';
    context.fillRect(-1, -1, size + 2, size + 2);
    context.fillStyle = 'black';
    context.font = metrics.font;
    // Compare pixels for test character to pixels for known character without a glyph
    context.fillText(i === 0 ? charOrCodePoint : '\uFFFE', 0, metrics.ascent);

    pixmaps[i] = context.getImageData(0, 0, size, size).data;
  }

  for (let i = 0; i < pixmaps[0].length; ++i) {
    if (pixmaps[0][i] !== pixmaps[1][i])
      return true;
  }

  return false;
}

Основная идея c - нарисовать символ на холст и посмотрите, отображает ли он те же пиксели или другие пиксели, чем известный несуществующий глиф, который обычно визуализируется как пустое поле. каждый неизвестный символ в виде индивидуально различимого небольшого прямоугольника с шестнадцатеричным значением кода Unicode внутри.

enter image description here

Хотя обычно это очень полезно, в данном конкретном случае , это большая проблема.

Кто-нибудь знает, как отключить эту функцию Firefox? Я искал Firefox -specifi c CSS функций, но я пришел пустым.

Или, если нет, может кто-нибудь предложить совершенно другой подход, чем мое сравнение холста уловка, чтобы определить, какие символьные кодовые точки имеют настоящие глифы, а какие нет?

1 Ответ

0 голосов
/ 10 марта 2020

Хотя я все еще готов к лучшему ответу, по крайней мере, сейчас у меня есть обходной путь.

Как оказалось, небольшая коробка показывается для отсутствующего глифа (будь то простой пустое поле или вариант Firefox с шестнадцатеричным кодом внутри) не изменяется курсивом CSS. Реальные, визуализированные символы, однако, заменены курсивом. Поэтому, если нормальный символ совпадает с его вариантом itali c, это не настоящий символ.

Я предпочитаю тест, который я использую для Chrome, поэтому я использую только этот альтернативный тест для Firefox.

function changeItalic(font: string): string {
  if (/\b(italic|oblique)\b/.test(font))
    return font.replace(/\b(italic|oblique)\b/, '');
  else
    return 'italic ' + font;
}

export function doesCharacterGlyphExist(elementOrFont: Element | string, charOrCodePoint: string | number): boolean {
  if (typeof charOrCodePoint === 'number')
    charOrCodePoint = String.fromCodePoint(charOrCodePoint);

  const metrics = getFontMetrics(elementOrFont);
  const PADDING = 8;
  const size = metrics.lineHeight + PADDING;

  const canvas0 = (doesCharacterGlyphExist as any).canvas0 || ((doesCharacterGlyphExist as any).canvas0 =
                  document.createElement('canvas') as HTMLCanvasElement);
  const canvas1 = (doesCharacterGlyphExist as any).canvas1 || ((doesCharacterGlyphExist as any).canvas1 =
                  document.createElement('canvas') as HTMLCanvasElement);
  const canvases = [canvas0, canvas1];
  const pixmaps = [];

  for (let i = 0; i < 2; ++i) {
    const canvas = canvases[i];

    canvas.width = size;
    canvas.height = size;
    canvas.style.opacity = '1';

    const context = canvas.getContext('2d');

    context.fillStyle = 'white';
    context.fillRect(-1, -1, size + 2, size + 2);
    context.fillStyle = 'black';
    // Compare pixels for test character to pixels for known character without a glyph.
    // For Firefox, which renders missing glyphs all differently, check if a character
    // looks the same as itself when rendered in italics -- the missing glyph boxes
    // remain straight when italicized.
    context.font = (i === 1 && isFirefox() ? changeItalic(metrics.font) : metrics.font);
    context.fillText(i === 0 || isFirefox() ? charOrCodePoint : '\uFFFE', 0, metrics.ascent);

    pixmaps[i] = context.getImageData(0, 0, size, size).data;
  }

  for (let i = 0; i < pixmaps[0].length; ++i) {
    if (pixmaps[0][i] !== pixmaps[1][i])
      return true;
  }

  return false;
}
...