@lightningjs/renderer
Version:
Lightning 3 Renderer
130 lines • 4.28 kB
JavaScript
/*
* 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 { calculateFontMetrics } from './Utils.js';
/**
* Global font set regardless of if run in the main thread or a web worker
*/
// const globalFontSet: FontFaceSet = (resolvedGlobal.document?.fonts ||
// (resolvedGlobal as unknown as { fonts: FontFaceSet }).fonts) as FontFaceSet;
// Global state variables for fontHandler
const fontFamilies = {};
const loadedFonts = new Set();
const fontLoadPromises = new Map();
const normalizedMetrics = new Map();
let initialized = false;
let context;
/**
* Normalize font metrics to be in the range of 0 to 1
*/
function normalizeMetrics(metrics) {
return {
ascender: metrics.ascender / metrics.unitsPerEm,
descender: metrics.descender / metrics.unitsPerEm,
lineGap: metrics.lineGap / metrics.unitsPerEm,
};
}
/**
* Check if a font can be rendered
*/
export const canRenderFont = () => {
// Canvas can always render any font family (assuming the browser supports it)
return true;
};
/**
* Load a font by providing fontFamily, fontUrl, and optional metrics
*/
export const loadFont = async (stage, options) => {
const { fontFamily, fontUrl, metrics } = options;
// If already loaded, return immediately
if (loadedFonts.has(fontFamily) === true) {
return;
}
const existingPromise = fontLoadPromises.get(fontFamily);
// If already loading, return the existing promise
if (existingPromise !== undefined) {
return existingPromise;
}
// Create and store the loading promise
const loadPromise = new FontFace(fontFamily, `url(${fontUrl})`)
.load()
.then((loadedFont) => {
document.fonts.add(loadedFont);
loadedFonts.add(fontFamily);
fontLoadPromises.delete(fontFamily);
// Store normalized metrics if provided
if (metrics) {
setFontMetrics(fontFamily, normalizeMetrics(metrics));
}
})
.catch((error) => {
fontLoadPromises.delete(fontFamily);
console.error(`Failed to load font: ${fontFamily}`, error);
throw error;
});
fontLoadPromises.set(fontFamily, loadPromise);
return loadPromise;
};
/**
* Get the font families map for resolving fonts
*/
export const getFontFamilies = () => {
return fontFamilies;
};
/**
* Initialize the global font handler
*/
export const init = (c) => {
if (initialized === true) {
return;
}
if (c === undefined) {
throw new Error('Canvas context is not provided for font handler initialization');
}
context = c;
// Register the default 'sans-serif' font face
const defaultMetrics = {
ascender: 0.8,
descender: -0.2,
lineGap: 0.2,
};
setFontMetrics('sans-serif', defaultMetrics);
loadedFonts.add('sans-serif');
initialized = true;
};
export const type = 'canvas';
/**
* Check if a font is already loaded by font family
*/
export const isFontLoaded = (fontFamily) => {
return loadedFonts.has(fontFamily) || fontFamily === 'sans-serif';
};
export const getFontMetrics = (fontFamily, fontSize) => {
let out = normalizedMetrics.get(fontFamily) ||
normalizedMetrics.get(fontFamily + fontSize);
if (out !== undefined) {
return out;
}
out = calculateFontMetrics(context, fontFamily, fontSize);
normalizedMetrics.set(fontFamily + fontSize, out);
return out;
};
export const setFontMetrics = (fontFamily, metrics) => {
normalizedMetrics.set(fontFamily, metrics);
};
//# sourceMappingURL=CanvasFontHandler.js.map