Skip to content

Update to Twemoji 16 for Emoji 16 support #8774

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

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,7 @@ module.exports = function(grunt) {
}

// Fetch a list of the files that Twemoji supplies.
query = 'query={repository(owner: "jdecked", name: "twemoji") {object(expression: "v15.1.0:assets/svg") {... on Tree {entries {name}}}}}';
query = 'query={repository(owner: "jdecked", name: "twemoji") {object(expression: "v16.0.1:assets/svg") {... on Tree {entries {name}}}}}';
files = spawn( 'gh', [ 'api', 'graphql', '-f', query] );

if ( 0 !== files.status ) {
Expand Down
92 changes: 63 additions & 29 deletions src/js/_enqueues/lib/emoji-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@
/**
* Checks if two sets of Emoji characters render the same visually.
*
* This is used to determine if the browser is rendering an emoji with multiple data points
* correctly. set1 is the emoji in the correct form, using a zero-width joiner. set2 is the emoji
* in the incorrect form, using a zero-width space. If the two sets render the same, then the browser
* does not support the emoji correctly.
*
* This function may be serialized to run in a Worker. Therefore, it cannot refer to variables from the containing
* scope. Everything must be passed by parameters.
*
Expand Down Expand Up @@ -160,6 +165,42 @@
} );
}

/**
* Checks if the center point of a single emoji is empty.
*
* This is used to determine if the browser is rendering an emoji with a single data point
* correctly. The center point of an incorrectly rendered emoji will be empty. A correctly
* rendered emoji will have a non-zero value at the center point.
*
* This function may be serialized to run in a Worker. Therefore, it cannot refer to variables from the containing
* scope. Everything must be passed by parameters.
*
* @since 6.8.2
*
* @private
*
* @param {CanvasRenderingContext2D} context 2D Context.
* @param {string} emoji Emoji to test.
*
* @return {boolean} True if the center point is empty.
*/
function emojiRendersEmptyCenterPoint( context, emoji ) {
// Cleanup from previous test.
context.clearRect( 0, 0, context.canvas.width, context.canvas.height );
context.fillText( emoji, 0, 0 );

// Test if the center point (16, 16) is empty (0,0,0,0).
var centerPoint = context.getImageData(16, 16, 1, 1);
for ( var i = 0; i < centerPoint.data.length; i++ ) {
if ( centerPoint.data[ i ] !== 0 ) {
// Stop checking the moment it's known not to be empty.
return false;
}
}

return true;
}

/**
* Determines if the browser properly renders Emoji that Twemoji can supplement.
*
Expand All @@ -173,10 +214,11 @@
* @param {CanvasRenderingContext2D} context 2D Context.
* @param {string} type Whether to test for support of "flag" or "emoji".
* @param {Function} emojiSetsRenderIdentically Reference to emojiSetsRenderIdentically function, needed due to minification.
* @param {Function} emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
*
* @return {boolean} True if the browser can render emoji, false if it cannot.
*/
function browserSupportsEmoji( context, type, emojiSetsRenderIdentically ) {
function browserSupportsEmoji( context, type, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint ) {
var isIdentical;

switch ( type ) {
Expand All @@ -198,16 +240,16 @@
}

/*
* Test for UN flag compatibility. This is the least supported of the letter locale flags,
* Test for Sark flag compatibility. This is the least supported of the letter locale flags,
* so gives us an easy test for full support.
*
* To test for support, we try to render it, and compare the rendering to how it would look if
* the browser doesn't render it correctly ([U] + [N]).
* the browser doesn't render it correctly ([C] + [Q]).
*/
isIdentical = emojiSetsRenderIdentically(
context,
'\uD83C\uDDFA\uD83C\uDDF3', // as the sequence of two code points
'\uD83C\uDDFA\u200B\uD83C\uDDF3' // as the two code points separated by a zero-width space
'\uD83C\uDDE8\uD83C\uDDF6', // as the sequence of two code points
'\uD83C\uDDE8\u200B\uD83C\uDDF6' // as the two code points separated by a zero-width space
);

if ( isIdentical ) {
Expand All @@ -232,31 +274,21 @@
return ! isIdentical;
case 'emoji':
/*
* Rise Like a Phoenix.
* Does Emoji 16.0 cause the browser to go splat?
*
* To test for Emoji 15.1 support, try to render a new emoji: Phoenix.
* To test for Emoji 16.0 support, try to render a new emoji: Splatter.
*
* A phoenix, a mythical immortal bird with flame-like feathers found in the folklore of many global
* cultures. Often used to symbolize renewal or rebirth.
* The splatter emoji is a single code point emoji. Testing for browser support
* required testing the center point of the emoji to see if it is empty.
*
* The Phoenix emoji is a ZWJ sequence combining 🐦 Bird, Zero Width Joiner and 🔥 Fire.
* These display as a single emoji on supported platforms.
* 0xD83E 0xDEDF (\uD83E\uDEDF) == 🫟 Splatter.
*
* 0xD83D 0xDC26 (\uD83D\uDC26) == 🐦 Bird
* 0x200D == Zero-Width Joiner (ZWJ) that links the code points for the new emoji or
* 0x200B == Zero-Width Space (ZWS) that is rendered for clients not supporting the new emoji.
* 0xD83D 0xDD25 (\uD83D\uDD25) == 🔥 Fire
*
* When updating this test for future Emoji releases, ensure that individual emoji that make up the
* sequence come from older emoji standards.
* When updating this test, please ensure that the emoji is either a single code point
* or switch to using the emojiSetsRenderIdentically function and testing with a zero-width
* joiner vs a zero-width space.
*/
isIdentical = emojiSetsRenderIdentically(
context,
'\uD83D\uDC26\u200D\uD83D\uDD25', // as the zero-width joiner sequence
'\uD83D\uDC26\u200B\uD83D\uDD25' // separated by a zero-width space
);

return ! isIdentical;
var notSupported = emojiRendersEmptyCenterPoint( context, '\uD83E\uDEDF' );
return ! notSupported;
}

return false;
Expand All @@ -275,10 +307,11 @@
* @param {string[]} tests Tests.
* @param {Function} browserSupportsEmoji Reference to browserSupportsEmoji function, needed due to minification.
* @param {Function} emojiSetsRenderIdentically Reference to emojiSetsRenderIdentically function, needed due to minification.
* @param {Function} emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
*
* @return {SupportTests} Support tests.
*/
function testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically ) {
function testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint ) {
var canvas;
if (
typeof WorkerGlobalScope !== 'undefined' &&
Expand All @@ -301,7 +334,7 @@

var supports = {};
tests.forEach( function ( test ) {
supports[ test ] = browserSupportsEmoji( context, test, emojiSetsRenderIdentically );
supports[ test ] = browserSupportsEmoji( context, test, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint );
} );
return supports;
}
Expand Down Expand Up @@ -354,7 +387,8 @@
[
JSON.stringify( tests ),
browserSupportsEmoji.toString(),
emojiSetsRenderIdentically.toString()
emojiSetsRenderIdentically.toString(),
emojiRendersEmptyCenterPoint.toString()
].join( ',' ) +
'));';
var blob = new Blob( [ workerScript ], {
Expand All @@ -371,7 +405,7 @@
} catch ( e ) {}
}

supportTests = testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically );
supportTests = testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint );
setSessionSupportTests( supportTests );
resolve( supportTests );
} )
Expand Down
Loading
Loading