Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not handle flag emoji on Windows #2

Open
MuTsunTsai opened this issue Nov 8, 2024 · 15 comments
Open

Does not handle flag emoji on Windows #2

MuTsunTsai opened this issue Nov 8, 2024 · 15 comments
Assignees
Labels
enhancement New feature or request

Comments

@MuTsunTsai
Copy link

Describe the bug
On Windows 10+, although there is native support for most of the emoji, the national flags such as 🇹🇼 are not really "supported" and one will only see two characters instead of the actual flag. For the moment Emoji-Fallback doesn't handle that, as it only checks whether "😃" is rendered correctly. It will be good if Emoji-Fallback can handle the flags separately.

@MarketingPip
Copy link
Member

@MuTsunTsai good catch! I will implement a solution for this. If you have any ideas of how to go about checking dynamically via regex or even a non regex solution (that doesn't use a table) would be much appreciated. Hope you are having a great weekend!

@MarketingPip
Copy link
Member

@MuTsunTsai - just to clarify too. Can you confirm on your browser (Windows 10) when ONLY using a national flag that the fallback support does NOT work on your device via a picture / screenshot? And if confirmed, do you know any other emojis that are not support in Windows? (Unicode 14 - etc...)

@MarketingPip MarketingPip self-assigned this Nov 10, 2024
@MarketingPip MarketingPip added the enhancement New feature or request label Nov 10, 2024
@MuTsunTsai
Copy link
Author

If you have any ideas of how to go about checking dynamically via regex

For the latest browsers, it will be /\p{RGI_Emoji_Flag_Sequence}/v, but the support is limited (see caniuse). For better browser compatibility, use /[\u{1f1e6}-\u{1f1ff}]{2}/u, or even /(?:\ud83c[\udde6-\uddff]){2}/.

Can you confirm on your browser (Windows 10) when ONLY using a national flag that the fallback support does NOT work on your device via a picture / screenshot?

image

Do you know any other emojis that are not support in Windows?

I just checked the list here, and the followings also are not rendered as emoji, but only as ugly Unicode characters.

☺ ↗ ↙ ↕ ↔ © ® ™ ▫ ▪

While the followings get rendered sometimes, but not always. (I don't know why. Maybe it depends on the context.)

♠️ ♥️ ♦️ ♣️ ↘ ↖ 〰

@MarketingPip
Copy link
Member

MarketingPip commented Nov 11, 2024

@MuTsunTsai - thank you very much.

Can I get you to possibly test this?

/*
Notes to self:
imageData = imageData[0] !== 0;  // Check if there's any color
imageData = imageData[3] !== 0;  // Check transparency (alpha channel)
*/ 
export const emojisSupported = () => {
  const emojiList = [
  '\ud83d\ude03', // 😀 Grinning Face with Smiling Eyes
  '\u1f1fa\u1f1f8', // 🇺🇸 United States Flag
  '👩‍🦰', // Woman with red hair
  '👨‍👩‍👧‍👦',  // Family emoji
  '👩',  // Single character (woman)
  '🫣'  // Face with peeking eye 
];
  
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  // Check if canvas and fillText method are available
  if (!ctx || typeof ctx.fillText !== 'function') {
    canvas.remove();
    return false;
  }

  ctx.textBaseline = 'top';
  ctx.font = '32px Arial';

  // Loop through the emojiList and check each emoji
  for (let emoji of emojiList) {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas before each test
    ctx.fillText(emoji, 0, 0);

    // Get the pixel data from the canvas at position (0, 0)
    let imageData = ctx.getImageData(0, 0, 1, 1).data;

    // Check if any pixels
    if (imageData[0] !== 0) {
      // Emoji is supported
      canvas.remove();
      return true;
    }
  }

  // No emoji in the list was supported
  canvas.remove();
  return false;
};
console.log(emojiSupported2())

@MuTsunTsai
Copy link
Author

@MarketingPip There are several issues with this code (other than the obvious typo of function name).

  1. It should be '\u{1f1fa}\u{1f1f8}' instead, as \uXXXX format only takes 4 characters that follows.
  2. This function seems to test "if any of the emoji is supported" rather than all of them, and I doubt that this is intended.
  3. By the way text is drawn on the canvas here, you naturally won't have anything at position (0,0) (see picture). You should be testing somewhere other than (0,0). In your codebase you test for (16,16) which seems like a good choice.
    image

Also, when it comes to cross-platform testing, I'd highly recommend BrowserStack. As an open-source project author, you can apply for their free plan here.

@MarketingPip
Copy link
Member

@MuTsunTsai - you do NOT need to draw ALL of them.. (this only draws 1 emoji and tests if it was rendered). Which that code above should cover newer version of emojis.

Please do verify with the function I gave you if you return a true statement...

@MuTsunTsai
Copy link
Author

@MarketingPip The function as it is, it returns false (especially because of point 3 I mentioned).
Now assuming that you changed it to test (16,16) instead. Then the very first emoji "😀" already makes the function returning true inside the loop, so the rest of the checks are pointless. Get it?

@MarketingPip
Copy link
Member

MarketingPip commented Nov 11, 2024

@MuTsunTsai - yo my bad, I sent you wrong code 🤦 (Thank you for bearing with me too)

/*
Notes to self:
imageData = imageData[0] !== 0;  // Check if there's any color
imageData = imageData[3] !== 0;  // Check transparency (alpha channel)
*/ 
export const emojiSupported2 = () => {
  const emojiList = [
  '\ud83d\ude03', // 😀 Grinning Face with Smiling Eyes
  '\u1f1fa\u1f1f8', // 🇺🇸 United States Flag
  '👩‍🦰', // Woman with red hair
  '👨‍👩‍👧‍👦',  // Family emoji
  '👩',  // Single character (woman)
  '🫣'  // Face with peeking eye 
];
  
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  // Check if canvas and fillText method are available
  if (!ctx || typeof ctx.fillText !== 'function') {
    canvas.remove();
    return false;
  }

  ctx.textBaseline = 'top';
  ctx.font = '32px Arial';

  // Loop through the emojiList and check each emoji
  for (let emoji of emojiList) {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas before each test
    ctx.fillText(emoji, 0, 0);

    // Get the pixel data from the canvas at position (0, 0)
    let imageData = ctx.getImageData(16, 16, 1, 1).data;
 
    // Check if any pixels
    if (imageData[0] !== 0) {
      // Emoji is supported
      canvas.remove();
      return true;
    }
  }

  // No emoji in the list was supported
  canvas.remove();
  return false;
};
console.log(emojiSupported2())
  • but you are correct on proper usage of the unicode etc. Being \u{1f1fa}\u{1f1f8} for proper ES6 syntax.

And I didn't catch what you were saying but I get what you mean now.

Would you prefer the code do a check like this?

export const emojiSupported2 = () => {
  const emojiList = [
  '\ud83d\ude03', // 😀 Grinning Face with Smiling Eyes
  '\u1f1fa\u1f1f8', // 🇺🇸 United States Flag
  '👩‍🦰', // Woman with red hair
  '👨‍👩‍👧‍👦',  // Family emoji
  '👩',  // Single character (woman)
  '🫣'  // Face with peeking eye 
];
  
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  // Check if canvas and fillText method are available
  if (!ctx || typeof ctx.fillText !== 'function') {
    canvas.remove();
    return false;
  }

  ctx.textBaseline = 'top';
  ctx.font = '32px Arial';

  // Loop through the emojiList and check each emoji
  for (let emoji of emojiList) {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas before each test
    ctx.fillText(emoji, 0, 0);

    // Get the pixel data from the canvas at position (0, 0)
    let imageData = ctx.getImageData(16, 16, 1, 1).data;
 
    // Check if any pixels
    if (imageData[0] === 0) {
      // Emoji is NOT supported
      canvas.remove();
      return false
    }
  }

  // All emoji in the list were supported
  canvas.remove();
  return true
};

@MarketingPip
Copy link
Member

@MuTsunTsai - see the above comment (we posted at same minute / second lol!)

@MuTsunTsai
Copy link
Author

@MarketingPip Yeah, the logic of the last version makes much more sense.

@MarketingPip
Copy link
Member

@MuTsunTsai - thank you! (my apologizes too for not understanding off first bat - and replying sounding like an assh*le above! - 2AM here lol).

Very good catch. I can gladly implement this or I more than welcome you too being you did help solve this issue. (If you would like to earn a PR etc - I just ask you to follow my style of commit messages / changes etc).

Feel free to let me know - if you're not interested, I can wrap this up by tomorrow 👍

@MuTsunTsai
Copy link
Author

@MarketingPip It's OK. Sure, I can certainly make a PR, but before that, I have one more suggestion.

Basically, as it is right now, it checks "whether any of the listed emojis is not supported", and if so, it will call the underlying twemoji and replace ALL emojis on the page. This seems overkill, however, for the present issue here. For Windows, it suffices to replace just the flags, as almost all the rest are supported. If you agree, this can be implemented as follows:

  1. Having at least two tests, one for the common emojis, and one for the flags (if the first test passes, that is; if the first test already fails there no need for this).
  2. If only the second test fails, call twemoji.parse with the options object instead, which one can assign a callback function to filter out those emojis that are not flags (see here for example), so that only flags are replaced.

Let me know if this sounds right, and then I will make the PR.

@MarketingPip
Copy link
Member

MarketingPip commented Nov 11, 2024

@MuTsunTsai - this seems more then reasonable to me! Please do verify on your system before making the PR that certain emojis are being parsed / replaced.

And please do use this commit message for changes to the source code:

Updated emoji-fallback.js 📥

@MuTsunTsai
Copy link
Author

@MarketingPip Done. Meanwhile, one more minor thing. According to the docs, the method twemoji.parse always runs synchronously, so there's no need to await it. (This is irrelevant to the present issue, so I didn't touch that part.)

@MarketingPip
Copy link
Member

@MuTsunTsai - parseEmoji() allows it to be awaited / tho is not needed. Reason why it allows to be awaited so developers can add support for example awaiting for emojis to render while loading screen etc... (OR if they prefer not too - simply just not use await infront)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants