first commit
This commit is contained in:
443
node_modules/lottie-web/player/js/utils/FontManager.js
generated
vendored
Normal file
443
node_modules/lottie-web/player/js/utils/FontManager.js
generated
vendored
Normal file
@@ -0,0 +1,443 @@
|
||||
import createNS from './helpers/svg_elements';
|
||||
import createTag from './helpers/html_elements';
|
||||
import getFontProperties from './getFontProperties';
|
||||
|
||||
const FontManager = (function () {
|
||||
var maxWaitingTime = 5000;
|
||||
var emptyChar = {
|
||||
w: 0,
|
||||
size: 0,
|
||||
shapes: [],
|
||||
data: {
|
||||
shapes: [],
|
||||
},
|
||||
};
|
||||
var combinedCharacters = [];
|
||||
// Hindi characters
|
||||
combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366,
|
||||
2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379,
|
||||
2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]);
|
||||
|
||||
var BLACK_FLAG_CODE_POINT = 127988;
|
||||
var CANCEL_TAG_CODE_POINT = 917631;
|
||||
var A_TAG_CODE_POINT = 917601;
|
||||
var Z_TAG_CODE_POINT = 917626;
|
||||
var VARIATION_SELECTOR_16_CODE_POINT = 65039;
|
||||
var ZERO_WIDTH_JOINER_CODE_POINT = 8205;
|
||||
var REGIONAL_CHARACTER_A_CODE_POINT = 127462;
|
||||
var REGIONAL_CHARACTER_Z_CODE_POINT = 127487;
|
||||
|
||||
var surrogateModifiers = [
|
||||
'd83cdffb',
|
||||
'd83cdffc',
|
||||
'd83cdffd',
|
||||
'd83cdffe',
|
||||
'd83cdfff',
|
||||
];
|
||||
|
||||
function trimFontOptions(font) {
|
||||
var familyArray = font.split(',');
|
||||
var i;
|
||||
var len = familyArray.length;
|
||||
var enabledFamilies = [];
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (familyArray[i] !== 'sans-serif' && familyArray[i] !== 'monospace') {
|
||||
enabledFamilies.push(familyArray[i]);
|
||||
}
|
||||
}
|
||||
return enabledFamilies.join(',');
|
||||
}
|
||||
|
||||
function setUpNode(font, family) {
|
||||
var parentNode = createTag('span');
|
||||
// Node is invisible to screen readers.
|
||||
parentNode.setAttribute('aria-hidden', true);
|
||||
parentNode.style.fontFamily = family;
|
||||
var node = createTag('span');
|
||||
// Characters that vary significantly among different fonts
|
||||
node.innerText = 'giItT1WQy@!-/#';
|
||||
// Visible - so we can measure it - but not on the screen
|
||||
parentNode.style.position = 'absolute';
|
||||
parentNode.style.left = '-10000px';
|
||||
parentNode.style.top = '-10000px';
|
||||
// Large font size makes even subtle changes obvious
|
||||
parentNode.style.fontSize = '300px';
|
||||
// Reset any font properties
|
||||
parentNode.style.fontVariant = 'normal';
|
||||
parentNode.style.fontStyle = 'normal';
|
||||
parentNode.style.fontWeight = 'normal';
|
||||
parentNode.style.letterSpacing = '0';
|
||||
parentNode.appendChild(node);
|
||||
document.body.appendChild(parentNode);
|
||||
|
||||
// Remember width with no applied web font
|
||||
var width = node.offsetWidth;
|
||||
node.style.fontFamily = trimFontOptions(font) + ', ' + family;
|
||||
return { node: node, w: width, parent: parentNode };
|
||||
}
|
||||
|
||||
function checkLoadedFonts() {
|
||||
var i;
|
||||
var len = this.fonts.length;
|
||||
var node;
|
||||
var w;
|
||||
var loadedCount = len;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (this.fonts[i].loaded) {
|
||||
loadedCount -= 1;
|
||||
} else if (this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0) {
|
||||
this.fonts[i].loaded = true;
|
||||
} else {
|
||||
node = this.fonts[i].monoCase.node;
|
||||
w = this.fonts[i].monoCase.w;
|
||||
if (node.offsetWidth !== w) {
|
||||
loadedCount -= 1;
|
||||
this.fonts[i].loaded = true;
|
||||
} else {
|
||||
node = this.fonts[i].sansCase.node;
|
||||
w = this.fonts[i].sansCase.w;
|
||||
if (node.offsetWidth !== w) {
|
||||
loadedCount -= 1;
|
||||
this.fonts[i].loaded = true;
|
||||
}
|
||||
}
|
||||
if (this.fonts[i].loaded) {
|
||||
this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent);
|
||||
this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime) {
|
||||
setTimeout(this.checkLoadedFontsBinded, 20);
|
||||
} else {
|
||||
setTimeout(this.setIsLoadedBinded, 10);
|
||||
}
|
||||
}
|
||||
|
||||
function createHelper(fontData, def) {
|
||||
var engine = (document.body && def) ? 'svg' : 'canvas';
|
||||
var helper;
|
||||
var fontProps = getFontProperties(fontData);
|
||||
if (engine === 'svg') {
|
||||
var tHelper = createNS('text');
|
||||
tHelper.style.fontSize = '100px';
|
||||
// tHelper.style.fontFamily = fontData.fFamily;
|
||||
tHelper.setAttribute('font-family', fontData.fFamily);
|
||||
tHelper.setAttribute('font-style', fontProps.style);
|
||||
tHelper.setAttribute('font-weight', fontProps.weight);
|
||||
tHelper.textContent = '1';
|
||||
if (fontData.fClass) {
|
||||
tHelper.style.fontFamily = 'inherit';
|
||||
tHelper.setAttribute('class', fontData.fClass);
|
||||
} else {
|
||||
tHelper.style.fontFamily = fontData.fFamily;
|
||||
}
|
||||
def.appendChild(tHelper);
|
||||
helper = tHelper;
|
||||
} else {
|
||||
var tCanvasHelper = new OffscreenCanvas(500, 500).getContext('2d');
|
||||
tCanvasHelper.font = fontProps.style + ' ' + fontProps.weight + ' 100px ' + fontData.fFamily;
|
||||
helper = tCanvasHelper;
|
||||
}
|
||||
function measure(text) {
|
||||
if (engine === 'svg') {
|
||||
helper.textContent = text;
|
||||
return helper.getComputedTextLength();
|
||||
}
|
||||
return helper.measureText(text).width;
|
||||
}
|
||||
return {
|
||||
measureText: measure,
|
||||
};
|
||||
}
|
||||
|
||||
function addFonts(fontData, defs) {
|
||||
if (!fontData) {
|
||||
this.isLoaded = true;
|
||||
return;
|
||||
}
|
||||
if (this.chars) {
|
||||
this.isLoaded = true;
|
||||
this.fonts = fontData.list;
|
||||
return;
|
||||
}
|
||||
if (!document.body) {
|
||||
this.isLoaded = true;
|
||||
fontData.list.forEach((data) => {
|
||||
data.helper = createHelper(data);
|
||||
data.cache = {};
|
||||
});
|
||||
this.fonts = fontData.list;
|
||||
return;
|
||||
}
|
||||
|
||||
var fontArr = fontData.list;
|
||||
var i;
|
||||
var len = fontArr.length;
|
||||
var _pendingFonts = len;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
var shouldLoadFont = true;
|
||||
var loadedSelector;
|
||||
var j;
|
||||
fontArr[i].loaded = false;
|
||||
fontArr[i].monoCase = setUpNode(fontArr[i].fFamily, 'monospace');
|
||||
fontArr[i].sansCase = setUpNode(fontArr[i].fFamily, 'sans-serif');
|
||||
if (!fontArr[i].fPath) {
|
||||
fontArr[i].loaded = true;
|
||||
_pendingFonts -= 1;
|
||||
} else if (fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3) {
|
||||
loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="' + fontArr[i].fFamily + '"], style[f-origin="3"][f-family="' + fontArr[i].fFamily + '"]');
|
||||
|
||||
if (loadedSelector.length > 0) {
|
||||
shouldLoadFont = false;
|
||||
}
|
||||
|
||||
if (shouldLoadFont) {
|
||||
var s = createTag('style');
|
||||
s.setAttribute('f-forigin', fontArr[i].fOrigin);
|
||||
s.setAttribute('f-origin', fontArr[i].origin);
|
||||
s.setAttribute('f-family', fontArr[i].fFamily);
|
||||
s.type = 'text/css';
|
||||
s.innerText = '@font-face {font-family: ' + fontArr[i].fFamily + "; font-style: normal; src: url('" + fontArr[i].fPath + "');}";
|
||||
defs.appendChild(s);
|
||||
}
|
||||
} else if (fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1) {
|
||||
loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]');
|
||||
|
||||
for (j = 0; j < loadedSelector.length; j += 1) {
|
||||
if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) {
|
||||
// Font is already loaded
|
||||
shouldLoadFont = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldLoadFont) {
|
||||
var l = createTag('link');
|
||||
l.setAttribute('f-forigin', fontArr[i].fOrigin);
|
||||
l.setAttribute('f-origin', fontArr[i].origin);
|
||||
l.type = 'text/css';
|
||||
l.rel = 'stylesheet';
|
||||
l.href = fontArr[i].fPath;
|
||||
document.body.appendChild(l);
|
||||
}
|
||||
} else if (fontArr[i].fOrigin === 't' || fontArr[i].origin === 2) {
|
||||
loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]');
|
||||
|
||||
for (j = 0; j < loadedSelector.length; j += 1) {
|
||||
if (fontArr[i].fPath === loadedSelector[j].src) {
|
||||
// Font is already loaded
|
||||
shouldLoadFont = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldLoadFont) {
|
||||
var sc = createTag('link');
|
||||
sc.setAttribute('f-forigin', fontArr[i].fOrigin);
|
||||
sc.setAttribute('f-origin', fontArr[i].origin);
|
||||
sc.setAttribute('rel', 'stylesheet');
|
||||
sc.setAttribute('href', fontArr[i].fPath);
|
||||
defs.appendChild(sc);
|
||||
}
|
||||
}
|
||||
fontArr[i].helper = createHelper(fontArr[i], defs);
|
||||
fontArr[i].cache = {};
|
||||
this.fonts.push(fontArr[i]);
|
||||
}
|
||||
if (_pendingFonts === 0) {
|
||||
this.isLoaded = true;
|
||||
} else {
|
||||
// On some cases even if the font is loaded, it won't load correctly when measuring text on canvas.
|
||||
// Adding this timeout seems to fix it
|
||||
setTimeout(this.checkLoadedFonts.bind(this), 100);
|
||||
}
|
||||
}
|
||||
|
||||
function addChars(chars) {
|
||||
if (!chars) {
|
||||
return;
|
||||
}
|
||||
if (!this.chars) {
|
||||
this.chars = [];
|
||||
}
|
||||
var i;
|
||||
var len = chars.length;
|
||||
var j;
|
||||
var jLen = this.chars.length;
|
||||
var found;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
j = 0;
|
||||
found = false;
|
||||
while (j < jLen) {
|
||||
if (this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch) {
|
||||
found = true;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
if (!found) {
|
||||
this.chars.push(chars[i]);
|
||||
jLen += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCharData(char, style, font) {
|
||||
var i = 0;
|
||||
var len = this.chars.length;
|
||||
while (i < len) {
|
||||
if (this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font) {
|
||||
return this.chars[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if (((typeof char === 'string' && char.charCodeAt(0) !== 13) || !char)
|
||||
&& console
|
||||
&& console.warn // eslint-disable-line no-console
|
||||
&& !this._warned
|
||||
) {
|
||||
this._warned = true;
|
||||
console.warn('Missing character from exported characters list: ', char, style, font); // eslint-disable-line no-console
|
||||
}
|
||||
return emptyChar;
|
||||
}
|
||||
|
||||
function measureText(char, fontName, size) {
|
||||
var fontData = this.getFontByName(fontName);
|
||||
// Using the char instead of char.charCodeAt(0)
|
||||
// to avoid collisions between equal chars
|
||||
var index = char;
|
||||
if (!fontData.cache[index]) {
|
||||
var tHelper = fontData.helper;
|
||||
if (char === ' ') {
|
||||
var doubleSize = tHelper.measureText('|' + char + '|');
|
||||
var singleSize = tHelper.measureText('||');
|
||||
fontData.cache[index] = (doubleSize - singleSize) / 100;
|
||||
} else {
|
||||
fontData.cache[index] = tHelper.measureText(char) / 100;
|
||||
}
|
||||
}
|
||||
return fontData.cache[index] * size;
|
||||
}
|
||||
|
||||
function getFontByName(name) {
|
||||
var i = 0;
|
||||
var len = this.fonts.length;
|
||||
while (i < len) {
|
||||
if (this.fonts[i].fName === name) {
|
||||
return this.fonts[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return this.fonts[0];
|
||||
}
|
||||
|
||||
function getCodePoint(string) {
|
||||
var codePoint = 0;
|
||||
var first = string.charCodeAt(0);
|
||||
if (first >= 0xD800 && first <= 0xDBFF) {
|
||||
var second = string.charCodeAt(1);
|
||||
if (second >= 0xDC00 && second <= 0xDFFF) {
|
||||
codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
|
||||
}
|
||||
}
|
||||
return codePoint;
|
||||
}
|
||||
|
||||
// Skin tone modifiers
|
||||
function isModifier(firstCharCode, secondCharCode) {
|
||||
var sum = firstCharCode.toString(16) + secondCharCode.toString(16);
|
||||
return surrogateModifiers.indexOf(sum) !== -1;
|
||||
}
|
||||
|
||||
function isZeroWidthJoiner(charCode) {
|
||||
return charCode === ZERO_WIDTH_JOINER_CODE_POINT;
|
||||
}
|
||||
|
||||
// This codepoint may change the appearance of the preceding character.
|
||||
// If that is a symbol, dingbat or emoji, U+FE0F forces it to be rendered
|
||||
// as a colorful image as compared to a monochrome text variant.
|
||||
function isVariationSelector(charCode) {
|
||||
return charCode === VARIATION_SELECTOR_16_CODE_POINT;
|
||||
}
|
||||
|
||||
// The regional indicator symbols are a set of 26 alphabetic Unicode
|
||||
/// characters (A–Z) intended to be used to encode ISO 3166-1 alpha-2
|
||||
// two-letter country codes in a way that allows optional special treatment.
|
||||
function isRegionalCode(string) {
|
||||
var codePoint = getCodePoint(string);
|
||||
if (codePoint >= REGIONAL_CHARACTER_A_CODE_POINT && codePoint <= REGIONAL_CHARACTER_Z_CODE_POINT) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some Emoji implementations represent combinations of
|
||||
// two “regional indicator” letters as a single flag symbol.
|
||||
function isFlagEmoji(string) {
|
||||
return isRegionalCode(string.substr(0, 2)) && isRegionalCode(string.substr(2, 2));
|
||||
}
|
||||
|
||||
function isCombinedCharacter(char) {
|
||||
return combinedCharacters.indexOf(char) !== -1;
|
||||
}
|
||||
|
||||
// Regional flags start with a BLACK_FLAG_CODE_POINT
|
||||
// folowed by 5 chars in the TAG range
|
||||
// and end with a CANCEL_TAG_CODE_POINT
|
||||
function isRegionalFlag(text, index) {
|
||||
var codePoint = getCodePoint(text.substr(index, 2));
|
||||
if (codePoint !== BLACK_FLAG_CODE_POINT) {
|
||||
return false;
|
||||
}
|
||||
var count = 0;
|
||||
index += 2;
|
||||
while (count < 5) {
|
||||
codePoint = getCodePoint(text.substr(index, 2));
|
||||
if (codePoint < A_TAG_CODE_POINT || codePoint > Z_TAG_CODE_POINT) {
|
||||
return false;
|
||||
}
|
||||
count += 1;
|
||||
index += 2;
|
||||
}
|
||||
return getCodePoint(text.substr(index, 2)) === CANCEL_TAG_CODE_POINT;
|
||||
}
|
||||
|
||||
function setIsLoaded() {
|
||||
this.isLoaded = true;
|
||||
}
|
||||
|
||||
var Font = function () {
|
||||
this.fonts = [];
|
||||
this.chars = null;
|
||||
this.typekitLoaded = 0;
|
||||
this.isLoaded = false;
|
||||
this._warned = false;
|
||||
this.initTime = Date.now();
|
||||
this.setIsLoadedBinded = this.setIsLoaded.bind(this);
|
||||
this.checkLoadedFontsBinded = this.checkLoadedFonts.bind(this);
|
||||
};
|
||||
Font.isModifier = isModifier;
|
||||
Font.isZeroWidthJoiner = isZeroWidthJoiner;
|
||||
Font.isFlagEmoji = isFlagEmoji;
|
||||
Font.isRegionalCode = isRegionalCode;
|
||||
Font.isCombinedCharacter = isCombinedCharacter;
|
||||
Font.isRegionalFlag = isRegionalFlag;
|
||||
Font.isVariationSelector = isVariationSelector;
|
||||
Font.BLACK_FLAG_CODE_POINT = BLACK_FLAG_CODE_POINT;
|
||||
|
||||
var fontPrototype = {
|
||||
addChars: addChars,
|
||||
addFonts: addFonts,
|
||||
getCharData: getCharData,
|
||||
getFontByName: getFontByName,
|
||||
measureText: measureText,
|
||||
checkLoadedFonts: checkLoadedFonts,
|
||||
setIsLoaded: setIsLoaded,
|
||||
};
|
||||
|
||||
Font.prototype = fontPrototype;
|
||||
|
||||
return Font;
|
||||
}());
|
||||
|
||||
export default FontManager;
|
Reference in New Issue
Block a user