UNPKG

@lightningjs/renderer

Version:
111 lines 4.89 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2025 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. */ import { CoreFont, FontState } from './CoreFont.js'; import { normalizeFontMetrics } from './TextLayoutEngine.js'; import { hasZeroWidthSpace } from './Utils.js'; export class CanvasFont extends CoreFont { measureContext; type = 'canvas'; url; constructor(textRenderer, props, measureContext) { super(textRenderer, props); this.measureContext = measureContext; this.url = props.url; this.metrics = props.metrics; } load() { if (this.state !== FontState.Created) { return; } this.state = FontState.Loading; const waitingNodes = this.waitingNodes; new FontFace(this.family, `url(${this.url})`) .load() .then((loadedFont) => { document.fonts.add(loadedFont); this.onLoaded(); }) .catch((error) => { this.state = FontState.Failed; console.error(`Failed to load font: ${this.family}`, error); this.emit('failed'); throw error; }); } measureText(text, letterSpacing) { if (letterSpacing === 0) { return this.measureContext.measureText(text).width; } if (hasZeroWidthSpace(text) === false) { return (this.measureContext.measureText(text).width + letterSpacing * text.length); } return text.split('').reduce((acc, char) => { if (hasZeroWidthSpace(char) === true) { return acc; } return acc + this.measureContext.measureText(char).width + letterSpacing; }, 0); } getMetrics(fontSize) { let m = this.normalizedMetrics[fontSize]; if (m !== undefined) { return m; } let metrics = this.metrics; if (metrics === undefined) { metrics = calculateCanvasMetrics(this.family, fontSize, this.measureContext); } m = this.normalizedMetrics[fontSize] = normalizeFontMetrics(metrics, fontSize); return m; } } function calculateCanvasMetrics(fontFamily, fontSize, measureContext) { // If the font face doesn't have metrics defined, we fallback to using the // browser's measureText method to calculate take a best guess at the font // actual font's metrics. // - fontBoundingBox[Ascent|Descent] is the best estimate but only supported // in Chrome 87+ (2020), Firefox 116+ (2023), and Safari 11.1+ (2018). // - It is an estimate as it can vary between browsers. // - actualBoundingBox[Ascent|Descent] is less accurate and supported in // Chrome 77+ (2019), Firefox 74+ (2020), and Safari 11.1+ (2018). // - If neither are supported, we'll use some default values which will // get text on the screen but likely not be great. // NOTE: It's been decided not to rely on fontBoundingBox[Ascent|Descent] // as it's browser support is limited and it also tends to produce higher than // expected values. It is instead HIGHLY RECOMMENDED that developers provide // explicit metrics in the font face definition. measureContext.font = `normal ${fontSize}px Unknown, ${fontFamily}`; const metrics = measureContext.measureText('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'); console.warn(`Font metrics not provided for Canvas Web font ${fontFamily}. ` + 'Using fallback values. It is HIGHLY recommended you use the latest ' + 'version of the Lightning 3 `msdf-generator` tool to extract the default ' + 'metrics for the font and provide them in the Canvas Web font definition.'); const ascender = metrics.fontBoundingBoxAscent ?? metrics.actualBoundingBoxAscent ?? 0; const descender = metrics.fontBoundingBoxDescent ?? metrics.actualBoundingBoxDescent ?? 0; return { ascender, descender: -descender, lineGap: (metrics.emHeightAscent ?? 0) + (metrics.emHeightDescent ?? 0) - (ascender + descender), unitsPerEm: (metrics.emHeightAscent ?? 0) + (metrics.emHeightDescent ?? 0), }; } //# sourceMappingURL=CanvasFont.js.map