UNPKG

@lightningtv/renderer

Version:
131 lines 4.85 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2023 Comcast Cable Communications Management, LLC. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const weightConversions = { normal: 400, bold: 700, bolder: 900, lighter: 100, }; const fontWeightToNumber = (weight) => { if (typeof weight === 'number') { return weight; } return weightConversions[weight] || 400; }; function resolveFontToUse(familyMapsByPriority, family, weightIn, style, stretch) { let weight = fontWeightToNumber(weightIn); for (const fontFamiles of familyMapsByPriority) { const fontFaces = fontFamiles[family]; if (!fontFaces) { continue; } if (fontFaces.size === 1) { // No Exact match found, find nearest weight match console.warn(`TrFontManager: Only one font face found for family: '${family}' - will be used for all weights and styles`); return fontFaces.values().next().value; } const weightMap = new Map(); for (const fontFace of fontFaces) { const fontFamilyWeight = fontWeightToNumber(fontFace.descriptors.weight); if (fontFamilyWeight === weight && fontFace.descriptors.style === style && fontFace.descriptors.stretch === stretch) { return fontFace; } weightMap.set(fontFamilyWeight, fontFace); } // No Exact match found, find nearest weight match const msg = `TrFontManager: No exact match: '${family} Weight: ${weight} Style: ${style} Stretch: ${stretch}'`; console.error(msg); // Follow the CSS font-weight algorithm to find the nearest weight match // https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-matching-algorithm if (weight === 400 && weightMap.has(500)) { return weightMap.get(500); } if (weight === 500 && weightMap.has(400)) { return weightMap.get(400); } if (weight < 400) { while (weight > 0) { if (weightMap.has(weight)) { return weightMap.get(weight); } weight -= 100; } // reset back for the next loop weight = 600; } while (weight < 1000) { if (weightMap.has(weight)) { return weightMap.get(weight); } weight += 100; } // finally check lower again weight = 500; while (weight > 0) { if (weightMap.has(weight)) { return weightMap.get(weight); } weight -= 100; } } return; } export class TrFontManager { textRenderers; fontCache = new Map(); constructor(textRenderers) { this.textRenderers = textRenderers; // Intentionally left blank } addFontFace(font) { // All the font face to all of the text renderers that support it for (const trId in this.textRenderers) { const tr = this.textRenderers[trId]; if (tr && tr.isFontFaceSupported(font)) { tr.addFontFace(font); } } } /** * Utility method to resolve a single font face from a list of prioritized family maps based on * a set of font properties. * * @remarks * These are to be used by a text renderer to resolve a font face if needed. * * @param familyMapsByPriority * @param props * @returns */ resolveFontFace(familyMapsByPriority, props, rendererType) { const { fontFamily, fontWeight, fontStyle, fontStretch } = props; const fontCacheString = `${rendererType}_${fontFamily}_${fontStyle}_${fontWeight}_${fontStretch}`; if (this.fontCache.has(fontCacheString) === true) { return this.fontCache.get(fontCacheString); } const resolvedFont = resolveFontToUse(familyMapsByPriority, fontFamily, fontWeight, fontStyle, fontStretch); if (resolvedFont !== undefined) { this.fontCache.set(fontCacheString, resolvedFont); } return resolvedFont; } } //# sourceMappingURL=TrFontManager.js.map