Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 92 additions & 24 deletions src/core/dom-renderer/domRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import * as lng from '@lightningjs/renderer';

import { EventEmitter } from '@lightningjs/renderer/utils';
import { Config } from '../config.js';
import { FontLoadOptions } from '../intrinsicTypes.js';
import type {
DomRendererMainSettings,
ExtractProps,
IRendererMain,
IRendererNode,
Expand All @@ -17,22 +19,20 @@ import type {
IRendererStage,
IRendererTextNode,
IRendererTextNodeProps,
DomRendererMainSettings,
} from './domRendererTypes.js';
import {
colorToRgba,
applyEasing,
applySubTextureScaling,
buildGradientStops,
colorToRgba,
compactString,
computeLegacyObjectFit,
applySubTextureScaling,
computeRenderStateForNode,
getNodeLineHeight,
applyEasing,
interpolateProp,
isRenderStateInBounds,
nodeHasTextureSource,
computeRenderStateForNode,
compactString,
} from './domRendererUtils.js';
import { FontLoadOptions } from '../intrinsicTypes.js';

// Feature detection for legacy brousers
const _styleRef: any =
Expand Down Expand Up @@ -315,11 +315,15 @@ function updateNodeStyles(node: DOMNode | DOMText) {
switch (textProps.contain) {
case 'width':
if (textProps.maxWidth && textProps.maxWidth > 0) {
style += `width: ${textProps.maxWidth}px;`;
if (node.textAlign === 'center') {
style += `width: ${textProps.maxWidth}px;`;
} else {
style += `max-width: ${textProps.maxWidth}px;`;
}
style += `overflow: hidden;`;
} else {
style += `width: 100%;`;
}
style += `overflow: hidden;`;
break;
case 'both': {
let lineHeight = getNodeLineHeight(textProps);
Expand Down Expand Up @@ -514,27 +518,84 @@ function updateNodeStyles(node: DOMNode | DOMText) {
let borderWidth = shaderProps['border-w'];
let borderColor = shaderProps['border-color'];
let borderGap = shaderProps['border-gap'] ?? 0;
let borderAlign = shaderProps['border-align'] ?? 'outside';
let borderAlign = shaderProps['border-align'] ?? 'inside';
let radius = shaderProps['radius'];

// Border
const borderWidthIsNumber = typeof borderWidth === 'number';
const borderWidthIsArray = Array.isArray(borderWidth);
const borderWidthHasValue =
(borderWidthIsNumber && borderWidth !== 0) ||
(borderWidthIsArray &&
(borderWidth as number[]).some(
(w) => typeof w === 'number' && w !== 0,
));

if (
typeof borderWidth === 'number' &&
borderWidth !== 0 &&
borderWidthHasValue &&
typeof borderColor === 'number' &&
borderColor !== 0
) {
const rgbaColor = colorToRgba(borderColor);

let gap = borderGap;
if (borderAlign === 'inside') {
gap = -(borderWidth + borderGap);
} else if (borderAlign === 'center') {
gap = -(borderWidth / 2) + borderGap;
}
if (borderWidthIsNumber) {
let insideWidth = 0;
let outsideWidth = 0;

borderStyle += `outline: ${borderWidth}px solid ${rgbaColor};`;
borderStyle += `outline-offset: ${gap}px;`;
if (borderAlign === 'inside') {
insideWidth = borderWidth;
} else if (borderAlign === 'center') {
insideWidth = borderWidth / 2;
outsideWidth = borderWidth / 2;
} else {
outsideWidth = borderWidth;
}

outsideWidth += borderGap;
insideWidth -= borderGap;

if (insideWidth < 0) {
outsideWidth += insideWidth;
insideWidth = 0;
}
if (outsideWidth < 0) {
insideWidth += outsideWidth;
outsideWidth = 0;
}

const shadows: string[] = [];
if (outsideWidth > 0) {
shadows.push(`0 0 0 ${outsideWidth}px ${rgbaColor}`);
}
if (insideWidth > 0) {
shadows.push(`inset 0 0 0 ${insideWidth}px ${rgbaColor}`);
}

if (shadows.length > 0) {
borderStyle += `box-shadow: ${shadows.join(', ')};`;
}
} else if (borderWidthIsArray) {
// Individual borders per side [top, right, bottom, left]
// Allow individual properties to override array values
const topWidth =
shaderProps['border-top'] ?? (borderWidth as number[])[0];
const rightWidth =
shaderProps['border-right'] ?? (borderWidth as number[])[1];
const bottomWidth =
shaderProps['border-bottom'] ?? (borderWidth as number[])[2];
const leftWidth =
shaderProps['border-left'] ?? (borderWidth as number[])[3];

const widths = [topWidth, rightWidth, bottomWidth, leftWidth];
const sides = ['top', 'right', 'bottom', 'left'] as const;

for (let i = 0; i < sides.length; i++) {
const width = widths[i];
if (typeof width === 'number' && width !== 0) {
borderStyle += `border-${sides[i]}: ${width}px solid ${rgbaColor};`;
}
}
}
}
// Rounded
if (typeof radius === 'number' && radius > 0) {
Expand Down Expand Up @@ -826,7 +887,6 @@ type Size = { width: number; height: number };

function getElSize(node: DOMNode): Size {
const rawRect = node.div.getBoundingClientRect();

const dpr = Config.rendererOptions?.deviceLogicalPixelRatio ?? 1;
let width = rawRect.width / dpr;
let height = rawRect.height / dpr;
Expand Down Expand Up @@ -857,28 +917,35 @@ function getElSize(node: DOMNode): Size {
*/
function updateDOMTextSize(node: DOMText): void {
let size: Size;
let dimensionsChanged = false;
switch (node.contain) {
case 'width':
size = getElSize(node);
if (node.props.w !== size.width) {
node.w = size.width;
dimensionsChanged = true;
}
if (node.props.h !== size.height) {
node.h = size.height;
dimensionsChanged = true;
}
break;
case 'none':
size = getElSize(node);
if (node.props.h !== size.height || node.props.w !== size.width) {
node.w = size.width;
node.h = size.height;
dimensionsChanged = true;
}
break;
}

if (!node.loaded) {
if (!node.loaded || dimensionsChanged) {
const payload: lng.NodeTextLoadedPayload = {
type: 'text',
dimensions: {
w: node.props.w,
h: node.props.h,
w: node.w,
h: node.h,
},
};
node.emit('loaded', payload);
Expand Down Expand Up @@ -1094,6 +1161,7 @@ export class DOMNode extends EventEmitter implements IRendererNode {
if (child !== child.stage.root) {
if (nodeHasTextureSource(child)) {
const nextState = computeRenderStateForNode(child);

if (nextState != null) {
child.updateRenderState(nextState);
}
Expand Down
1 change: 0 additions & 1 deletion src/core/dom-renderer/domRendererTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ export interface IRendererMain extends IEventEmitter {
createNode(props: Partial<IRendererNodeProps>): IRendererNode;
createShader: typeof lng.RendererMain.prototype.createShader;
createTexture: typeof lng.RendererMain.prototype.createTexture;
//createEffect: typeof lng.RendererMain.prototype.createEffect;
}

export interface DomRendererMainSettings {
Expand Down
5 changes: 4 additions & 1 deletion src/core/elementNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ export class ElementNode extends Object {
if (this.rendered) {
if (!this.lng.shader) {
this.lng.shader = Config.convertToShader(this, target);
} else if (DOM_RENDERING) {
} else if (DOM_RENDERING && Config.domRendererEnabled) {
this.lng.shader = this.lng.shader; // lng.shader is a setter, force style update
}
} else {
Expand Down Expand Up @@ -1557,6 +1557,7 @@ export function shaderAccessor<T extends Record<string, any> | number>(
this._effects[key] = value;

let animationSettings: AnimationSettings | undefined;

if (this.lng.shader?.props) {
target = this.lng.shader.props;
const transitionKey = key === 'rounded' ? 'borderRadius' : key;
Expand All @@ -1583,6 +1584,8 @@ export function shaderAccessor<T extends Record<string, any> | number>(
if (this.rendered) {
if (!this.lng.shader) {
this.lng.shader = Config.convertToShader(this, target);
} else if (DOM_RENDERING && Config.domRendererEnabled) {
this.lng.shader = this.lng.shader; // lng.shader is a setter, force style update
}
} else {
this.lng.shader = target;
Expand Down
4 changes: 2 additions & 2 deletions src/core/lightningInit.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as lng from '@lightningjs/renderer';
import { DOMRendererMain, loadFontToDom } from './dom-renderer/domRenderer.js';
import { Config, DOM_RENDERING } from './config.js';
import { FontLoadOptions } from './intrinsicTypes.js';
import { DOMRendererMain, loadFontToDom } from './dom-renderer/domRenderer.js';
import { DomRendererMainSettings } from './dom-renderer/domRendererTypes.js';
import { FontLoadOptions } from './intrinsicTypes.js';

export type SdfFontType = 'ssdf' | 'msdf';
// Global renderer instance: can be either the Lightning or DOM implementation
Expand Down
20 changes: 10 additions & 10 deletions src/core/shaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export {
};
export { WebGlShader };

import { DOM_RENDERING, SHADERS_ENABLED } from './config.js';
import { Config, DOM_RENDERING, SHADERS_ENABLED } from './config.js';
import type { CoreShaderManager } from './intrinsicTypes.js';
import { IRendererShaderManager } from './dom-renderer/domRendererTypes.js';

Expand Down Expand Up @@ -122,17 +122,17 @@ function toValidVec4(value: unknown): Vec4 {
export function registerDefaultShaderRounded(
shManager: IRendererShaderManager,
) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType('rounded', defaultShaderRounded);
}
export function registerDefaultShaderShadow(shManager: CoreShaderManager) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType('shadow', defaultShaderShadow);
}
export function registerDefaultShaderRoundedWithBorder(
shManager: CoreShaderManager,
) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType(
'roundedWithBorder',
defaultShaderRoundedWithBorder,
Expand All @@ -141,7 +141,7 @@ export function registerDefaultShaderRoundedWithBorder(
export function registerDefaultShaderRoundedWithShadow(
shManager: CoreShaderManager,
) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType(
'roundedWithShadow',
defaultShaderRoundedWithShadow,
Expand All @@ -150,31 +150,31 @@ export function registerDefaultShaderRoundedWithShadow(
export function registerDefaultShaderRoundedWithBorderAndShadow(
shManager: CoreShaderManager,
) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType(
'roundedWithBorderWithShadow',
defaultShaderRoundedWithBorderAndShadow,
);
}
export function registerDefaultShaderHolePunch(shManager: CoreShaderManager) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType('holePunch', defaultShaderHolePunch);
}
export function registerDefaultShaderRadialGradient(
shManager: CoreShaderManager,
) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType('radialGradient', defaultShaderRadialGradient);
}
export function registerDefaultShaderLinearGradient(
shManager: CoreShaderManager,
) {
if (SHADERS_ENABLED && !DOM_RENDERING)
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled))
shManager.registerShaderType('linearGradient', defaultShaderLinearGradient);
}

export function registerDefaultShaders(shManager: CoreShaderManager) {
if (SHADERS_ENABLED && !DOM_RENDERING) {
if (SHADERS_ENABLED && !(DOM_RENDERING && Config.domRendererEnabled)) {
registerDefaultShaderRounded(shManager);
registerDefaultShaderShadow(shManager);
registerDefaultShaderRoundedWithBorder(shManager);
Expand Down