@lightningjs/renderer
Version:
Lightning 3 Renderer
183 lines • 7 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';
import { wrapText, wrapWord, measureText, calcHeight } from './Utils.js';
import { getFontMetrics, setFontMetrics } from '../CanvasFontHandler.js';
export function calculateRenderInfo(context, renderInfo) {
const precision = renderInfo.precision;
const paddingLeft = renderInfo.paddingLeft * precision;
const paddingRight = renderInfo.paddingRight * precision;
const fontSize = renderInfo.fontSize * precision;
let offsetY = renderInfo.offsetY === null ? null : renderInfo.offsetY * precision;
const w = renderInfo.width * precision;
const h = renderInfo.height * precision;
let wordWrapWidth = renderInfo.wordWrapWidth * precision;
const cutSx = renderInfo.cutSx * precision;
const cutEx = renderInfo.cutEx * precision;
const cutSy = renderInfo.cutSy * precision;
const cutEy = renderInfo.cutEy * precision;
const letterSpacing = (renderInfo.letterSpacing || 0) * precision;
const textIndent = renderInfo.textIndent * precision;
const fontFamily = renderInfo.fontFamily;
// Set font properties
context.font = `${renderInfo.fontStyle} ${fontSize}px ${fontFamily}`;
context.textBaseline = renderInfo.textBaseline;
let metrics = getFontMetrics(fontFamily, fontSize);
if (metrics === null) {
metrics = calculateFontMetrics(context, fontFamily, fontSize);
setFontMetrics(fontFamily, metrics);
}
const defLineHeight = fontSize *
(metrics.ascender - metrics.descender + metrics.lineGap) *
precision;
const lineHeight = renderInfo.lineHeight !== null
? renderInfo.lineHeight * precision
: defLineHeight;
const maxHeight = renderInfo.maxHeight;
const containedMaxLines = maxHeight !== null && lineHeight > 0
? Math.floor(maxHeight / lineHeight)
: 0;
const setMaxLines = renderInfo.maxLines;
const calcMaxLines = containedMaxLines > 0 && setMaxLines > 0
? Math.min(containedMaxLines, setMaxLines)
: Math.max(containedMaxLines, setMaxLines);
const textOverflow = renderInfo.textOverflow;
const wordWrap = renderInfo.wordWrap;
// Total width
let width = w || 2048 / precision;
// Inner width
let innerWidth = width - paddingLeft;
if (innerWidth < 10) {
width += 10 - innerWidth;
innerWidth = 10;
}
if (wordWrapWidth === 0) {
wordWrapWidth = innerWidth;
}
// Text overflow
let text = renderInfo.text;
if (textOverflow !== null && wordWrap === false) {
let suffix;
switch (textOverflow) {
case 'clip':
suffix = '';
break;
case 'ellipsis':
suffix = renderInfo.overflowSuffix;
break;
default:
suffix = String(textOverflow);
}
text = wrapWord(context, text, wordWrapWidth - textIndent, suffix, letterSpacing);
}
// Word wrap
let linesInfo;
if (wordWrap) {
linesInfo = wrapText(context, text, wordWrapWidth, letterSpacing, textIndent);
}
else {
linesInfo = { l: text.split(/(?:\r\n|\r|\n)/), n: [] };
const n = linesInfo.l.length;
for (let i = 0; i < n - 1; i++) {
linesInfo.n.push(i);
}
}
let lines = linesInfo.l;
let remainingText = '';
let moreTextLines = false;
if (calcMaxLines > 0 && lines.length > calcMaxLines) {
const usedLines = lines.slice(0, calcMaxLines);
let otherLines = [];
const overflowSuffix = renderInfo.overflowSuffix;
if (overflowSuffix.length > 0) {
const w = measureText(context, overflowSuffix, letterSpacing);
const al = wrapText(context, usedLines[usedLines.length - 1], wordWrapWidth - w, letterSpacing, textIndent);
usedLines[usedLines.length - 1] = `${al.l[0]}${overflowSuffix}`;
otherLines = [al.l.length > 1 ? al.l[1] : ''];
}
else {
otherLines = [''];
}
// Re-assemble the remaining text
let i;
const n = lines.length;
let j = 0;
const m = linesInfo.n.length;
for (i = calcMaxLines; i < n; i++) {
otherLines[j] += `${otherLines[j] ? ' ' : ''}${lines[i] ?? ''}`;
if (i + 1 < m && linesInfo.n[i + 1] !== undefined) {
j++;
}
}
remainingText = otherLines.join('\n');
moreTextLines = true;
lines = usedLines;
}
// Calculate text width
let maxLineWidth = 0;
const lineWidths = [];
for (let i = 0; i < lines.length; i++) {
const lineWidth = measureText(context, lines[i], letterSpacing) +
(i === 0 ? textIndent : 0);
lineWidths.push(lineWidth);
maxLineWidth = Math.max(maxLineWidth, lineWidth);
}
if (w === 0) {
width = maxLineWidth + paddingLeft + paddingRight;
innerWidth = maxLineWidth;
}
if (wordWrap === true &&
w > maxLineWidth &&
renderInfo.textAlign === 'left' &&
lines.length === 1) {
width = maxLineWidth + paddingLeft + paddingRight;
}
let height;
if (h > 0) {
height = h;
}
else {
height = calcHeight(renderInfo.textBaseline, fontSize, lineHeight, lines.length, offsetY);
}
if (offsetY === null) {
offsetY = fontSize;
}
renderInfo.width = width;
renderInfo.height = height;
renderInfo.lines = lines;
renderInfo.precision = precision;
renderInfo.remainingText = remainingText;
renderInfo.moreTextLines = moreTextLines;
renderInfo.innerWidth = innerWidth;
renderInfo.fontSize = fontSize;
renderInfo.cutSx = cutSx;
renderInfo.cutSy = cutSy;
renderInfo.cutEx = cutEx;
renderInfo.cutEy = cutEy;
renderInfo.lineHeight = lineHeight;
renderInfo.defLineHeight = defLineHeight;
renderInfo.lineWidths = lineWidths;
renderInfo.offsetY = offsetY;
renderInfo.paddingLeft = paddingLeft;
renderInfo.paddingRight = paddingRight;
renderInfo.letterSpacing = letterSpacing;
renderInfo.textIndent = textIndent;
renderInfo.metrics = metrics;
}
//# sourceMappingURL=calculateRenderInfo.js.map