fix: fix missing emoji on some android versions

This commit is contained in:
Nolan Lawson 2020-06-15 14:40:16 -07:00
parent eee18e4594
commit 76f142dff7
9 changed files with 69 additions and 48 deletions

View File

@ -1,12 +1,15 @@
import allEmoji from 'emojibase-data/en/data.json'
const versions = [...new Set(allEmoji.map(_ => _.version))].sort((a, b) => a < b ? -1 : 1)
export const versionsAndTestEmoji = Object.fromEntries(versions.map(version => {
// find one good representative emoji to test. Ideally its should be one that's short
const emoji = allEmoji.find(_ => _.version === version).emoji
return [
emoji,
version
]
}))
// Find one good representative emoji to test. Ideally it should have color in the center.
// For some inspiration, see: https://about.gitlab.com/blog/2018/05/30/journey-in-native-unicode-emoji/
export const versionsAndTestEmoji = {
'😃': 0.6,
'😐️': 0.7,
'😀': 1,
'👁️‍🗨️': 2,
'🤣': 3,
'👱‍♀️': 4,
'🤩': 5,
'🥰': 11, // smiling face with hearts
'🥻': 12, // sari
'🧑‍🦰': 12.1, // person: red hair
'🥲': 13 // smiling face with tear
}

View File

@ -1,7 +1,6 @@
import '@testing-library/jest-dom/extend-expect'
import 'fake-indexeddb/auto'
import { Crypto } from '@peculiar/webcrypto'
import { versionsAndTestEmoji } from '../bin/versionsAndTestEmoji'
jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox())
jest.setTimeout(60000)
@ -11,4 +10,3 @@ global.Response = fetch.Response
global.crypto = new Crypto()
process.env.NODE_ENV = 'test'
process.env.VERSIONS_AND_TEST_EMOJI = JSON.stringify(versionsAndTestEmoji)

View File

@ -69,7 +69,6 @@
"fetch-mock-jest": "^1.3.0",
"focus-visible": "^5.1.0",
"husky": "^4.2.5",
"if-emoji": "^0.1.0",
"jest": "^26.0.1",
"lint-staged": "^10.2.7",
"lodash-es": "^4.17.15",

View File

@ -4,7 +4,6 @@ import replace from '@rollup/plugin-replace'
import mainSvelte from 'rollup-plugin-svelte'
import hotSvelte from 'rollup-plugin-svelte-hot'
import autoPreprocess from 'svelte-preprocess'
import { versionsAndTestEmoji } from './bin/versionsAndTestEmoji'
import analyze from 'rollup-plugin-analyzer'
const dev = process.env.NODE_ENV !== 'production'
@ -18,8 +17,7 @@ const baseConfig = {
cjs(),
replace({
'process.env.NODE_ENV': dev ? '"development"' : '"production"',
'process.env.PERF': !!process.env.PERF,
'process.env.VERSIONS_AND_TEST_EMOJI': JSON.stringify(versionsAndTestEmoji)
'process.env.PERF': !!process.env.PERF
}),
replace({
'\'../database/Database.js\'': '\'./database.js\'',

View File

@ -16,7 +16,7 @@ import { incrementOrDecrement } from '../../utils/incrementOrDecrement'
import { tick } from 'svelte'
import {
DEFAULT_NUM_COLUMNS,
DEFAULT_SKIN_TONE_EMOJI,
DEFAULT_SKIN_TONE_EMOJI, FONT_FAMILY,
MOST_COMMONLY_USED_EMOJI,
TIMEOUT_BEFORE_LOADING_MESSAGE
} from '../../constants'
@ -140,6 +140,7 @@ Promise.resolve().then(() => {
//
$: style = `
--font-family: ${FONT_FAMILY};
--num-categories: ${categories.length};
--indicator-opacity: ${searchMode ? 0 : 1};
--num-skintones: ${NUM_SKIN_TONES};`

View File

@ -78,15 +78,7 @@ button.emoji,
width: var(--total-emoji-size);
line-height: 1;
overflow: hidden;
font-family:
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Twemoji Mozilla",
"Noto Color Emoji",
"EmojiOne Color",
"Android Emoji",
sans-serif;
font-family: var(--font-family);
&:hover {
background: var(--button-hover-background);

View File

@ -22,3 +22,6 @@ export const MOST_COMMONLY_USED_EMOJI = [
'🙌',
'😘'
]
export const FONT_FAMILY = '"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol",' +
'"Twemoji Mozilla","Noto Color Emoji","EmojiOne Color","Android Emoji",sans-serif'

View File

@ -1,30 +1,19 @@
// rather than check every emoji ever, which would be expensive, just check some representatives from the
// different emoji releases to determine what the font supports
import isEmoji from 'if-emoji/src/index.js'
import { mark, stop } from '../../shared/marks'
// In production mode, preprocess the file so we don't have to run a bunch of logic and can
// just directly inject the JSON object itself. In Jest, this is a JSON string.
const versionsAndTestEmoji = process.env.NODE_ENV === 'test'
? JSON.parse(process.env.VERSIONS_AND_TEST_EMOJI)
: process.env.VERSIONS_AND_TEST_EMOJI
import { versionsAndTestEmoji } from '../../../bin/versionsAndTestEmoji'
import { testColorEmojiSupported } from './testColorEmojiSupported'
export function determineEmojiSupportLevel () {
mark('determineEmojiSupportLevel')
const testEmoji = process.env.NODE_ENV === 'test'
? () => Math.max(...Object.values(versionsAndTestEmoji))
: isEmoji // avoid using Canvas in Jest, just say we support all emoji
const versionsWithSupports = Object.entries(versionsAndTestEmoji).map(([emoji, version]) => {
const supported = testEmoji(emoji)
return {
version,
supported
let res
for (const [emoji, version] of Object.entries(versionsAndTestEmoji)) {
if (testColorEmojiSupported(emoji)) {
res = version
} else {
break
}
})
const res = versionsWithSupports
.filter(_ => _.supported)
.map(_ => _.version)
.sort((a, b) => a < b ? 1 : -1)[0]
}
stop('determineEmojiSupportLevel')
return res
}

View File

@ -0,0 +1,38 @@
// Test if an emoji is supported by rendering it to canvas and checking that the color is not black
// See https://about.gitlab.com/blog/2018/05/30/journey-in-native-unicode-emoji/
// and https://www.npmjs.com/package/if-emoji for inspiration
// This implementation is largely borrowed from if-emoji, adding the font-family
import { FONT_FAMILY } from '../constants'
const getTextFeature = (text, color) => {
try {
const canvas = document.createElement('canvas')
canvas.width = canvas.height = 1
const ctx = canvas.getContext('2d')
ctx.textBaseline = 'top'
ctx.font = `100px ${FONT_FAMILY}`
ctx.fillStyle = color
ctx.scale(0.01, 0.01)
ctx.fillText(text, 0, 0)
return ctx.getImageData(0, 0, 1, 1).data
} catch (e) { /* ignore, return undefined */ }
}
const compareFeatures = (feature1, feature2) => {
const feature1Str = [...feature1].join(',')
const feature2Str = [...feature2].join(',')
return feature1Str === feature2Str && feature1Str !== '0,0,0,0'
}
export function testColorEmojiSupported (text) {
if (process.env.NODE_ENV === 'test') {
return true // avoid using canvas in jest
}
// Render white and black and then compare them to each other and ensure they're the same
// color, and neither one is black. This shows that the emoji was rendered in color.
const feature1 = getTextFeature(text, '#000')
const feature2 = getTextFeature(text, '#fff')
return feature1 && feature2 && compareFeatures(feature1, feature2)
}