WordPress/wp-includes/js/wp-emoji-loader.js
Peter Wilson e73ba84b04 Emoji: Load polyfill responsibly.
Improve performance of Emoji tests and loading of the polyfill.

Reduces the number of tests to determine browser support for emoji to those most likely to fail. Adds the defer flag to the loaded scripts for browsers lacking support.

Props superpoincare for perf testing, peterwilsoncc.
Fixes #37817.

Built from https://develop.svn.wordpress.org/trunk@38869


git-svn-id: http://core.svn.wordpress.org/trunk@38812 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-10-23 00:00:34 +00:00

156 lines
4.9 KiB
JavaScript

( function( window, document, settings ) {
var src, ready, ii, tests;
/*
* Create a canvas element for testing native browser support
* of emoji.
*/
var canvas = document.createElement( 'canvas' );
var context = canvas.getContext && canvas.getContext( '2d' );
/**
* Detect if the browser supports rendering emoji or flag emoji. Flag emoji are a single glyph
* made of two characters, so some browsers (notably, Firefox OS X) don't support them.
*
* @since 4.2.0
*
* @param type {String} Whether to test for support of "flag" or "emoji4" emoji.
* @return {Boolean} True if the browser can render emoji, false if it cannot.
*/
function browserSupportsEmoji( type ) {
var stringFromCharCode = String.fromCharCode,
flag, flag2, technologist, technologist2;
if ( ! context || ! context.fillText ) {
return false;
}
// Cleanup from previous test.
context.clearRect( 0, 0, canvas.width, canvas.height );
/*
* Chrome on OS X added native emoji rendering in M41. Unfortunately,
* it doesn't work when the font is bolder than 500 weight. So, we
* check for bold rendering support to avoid invisible emoji in Chrome.
*/
context.textBaseline = 'top';
context.font = '600 32px Arial';
switch ( type ) {
case 'flag':
/*
* This works because the image will be one of three things:
* - Two empty squares, if the browser doesn't render emoji
* - Two squares with 'U' and 'N' in them, if the browser doesn't render flag emoji
* - The United Nations flag
*
* The first two will encode to small images (1-2KB data URLs), the third will encode
* to a larger image (4-5KB data URL).
*/
context.fillText( stringFromCharCode( 55356, 56826, 55356, 56819 ), 0, 0 );
if ( canvas.toDataURL().length < 3000 ) {
return false;
}
context.clearRect( 0, 0, canvas.width, canvas.height );
/*
* Test for rainbow flag compatibility. As the rainbow flag was added out of sequence with
* the usual Unicode release cycle, some browsers support it, and some don't, even if their
* Unicode support is up to date.
*
* 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 (white flag emoji + rainbow emoji).
*/
context.fillText( stringFromCharCode( 55356, 57331, 65039, 8205, 55356, 57096 ), 0, 0 );
flag = canvas.toDataURL();
context.clearRect( 0, 0, canvas.width, canvas.height );
context.fillText( stringFromCharCode( 55356, 57331, 55356, 57096 ), 0, 0 );
flag2 = canvas.toDataURL();
return flag !== flag2;
case 'emoji4':
/*
* Emoji 4 has the best technologists. So does WordPress!
*
* To test for support, try to render a new emoji (woman technologist: medium skin tone),
* then compare it to how it would look if the browser doesn't render it correctly
* (woman technologist: medium skin tone + personal computer).
*/
context.fillText( stringFromCharCode( 55357, 56425, 55356, 57341, 8205, 55357, 56507), 0, 0 );
technologist = canvas.toDataURL();
context.clearRect( 0, 0, canvas.width, canvas.height );
context.fillText( stringFromCharCode( 55357, 56425, 55356, 57341, 55357, 56507), 0, 0 );
technologist2 = canvas.toDataURL();
return technologist !== technologist2;
}
return false;
}
function addScript( src ) {
var script = document.createElement( 'script' );
script.src = src;
script.defer = script.type = 'text/javascript';
document.getElementsByTagName( 'head' )[0].appendChild( script );
}
tests = Array( 'flag', 'emoji4' );
settings.supports = {
everything: true,
everythingExceptFlag: true
};
for( ii = 0; ii < tests.length; ii++ ) {
settings.supports[ tests[ ii ] ] = browserSupportsEmoji( tests[ ii ] );
settings.supports.everything = settings.supports.everything && settings.supports[ tests[ ii ] ];
if ( 'flag' !== tests[ ii ] ) {
settings.supports.everythingExceptFlag = settings.supports.everythingExceptFlag && settings.supports[ tests[ ii ] ];
}
}
settings.supports.everythingExceptFlag = settings.supports.everythingExceptFlag && ! settings.supports.flag;
settings.DOMReady = false;
settings.readyCallback = function() {
settings.DOMReady = true;
};
if ( ! settings.supports.everything ) {
ready = function() {
settings.readyCallback();
};
if ( document.addEventListener ) {
document.addEventListener( 'DOMContentLoaded', ready, false );
window.addEventListener( 'load', ready, false );
} else {
window.attachEvent( 'onload', ready );
document.attachEvent( 'onreadystatechange', function() {
if ( 'complete' === document.readyState ) {
settings.readyCallback();
}
} );
}
src = settings.source || {};
if ( src.concatemoji ) {
addScript( src.concatemoji );
} else if ( src.wpemoji && src.twemoji ) {
addScript( src.twemoji );
addScript( src.wpemoji );
}
}
} )( window, document, window._wpemojiSettings );