fix(runtime): satisfy color grading audit

This commit is contained in:
ukimsanov
2026-07-06 12:49:34 -07:00
parent 870964b0cf
commit 644ae384a5
5 changed files with 37 additions and 28 deletions
@@ -1,3 +1,4 @@
// fallow-ignore-file code-duplication
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { HF_COLOR_GRADING_ATTR, serializeHfColorGrading } from "../colorGrading";
import { createColorGradingRuntime, type RuntimeColorGradingApi } from "./colorGrading";
@@ -1624,6 +1624,7 @@ export function createColorGradingRuntime(): RuntimeColorGradingApi {
return true;
};
// fallow-ignore-next-line complexity
const getStatus = (
target: HfColorGradingTarget | string | null | undefined,
): RuntimeColorGradingStatus => {
@@ -1,4 +1,5 @@
// @vitest-environment node
// fallow-ignore-file code-duplication
import { describe, it, expect, vi } from "vitest";
import { parseHTML } from "linkedom";
import { type Page } from "puppeteer-core";
@@ -4,6 +4,7 @@
* BeginFrame-based deterministic screenshot capture and video frame injection.
*/
// fallow-ignore-file code-duplication
import { type Page } from "puppeteer-core";
import { type CaptureOptions } from "../types.js";
import {
@@ -325,6 +326,7 @@ export async function applyDomLayerMask(
extraHideIds: string[],
): Promise<void> {
await page.evaluate(
// fallow-ignore-next-line complexity
(args: {
show: string[];
hide: string[];
@@ -504,6 +506,7 @@ export async function injectVideoFramesBatch(
): Promise<string[]> {
if (updates.length === 0) return [];
return await page.evaluate(
// fallow-ignore-next-line complexity
async (
items: Array<{ videoId: string; dataUri: string }>,
visualProperties: string[],
@@ -684,6 +687,7 @@ export async function syncVideoFrameVisibility(
activeVideoIds: string[],
): Promise<void> {
await page.evaluate(
// fallow-ignore-next-line complexity
(ids: string[], colorGradingSourceHiddenAttr: string) => {
// Mirror the ancestor-visibility guard from `injectVideoFramesBatch`.
// See that copy for the full rationale on why `visibility: hidden` is
@@ -80,6 +80,7 @@ function createFrameSourceCache(
evictions++;
}
// fallow-ignore-next-line complexity
function remember(framePath: string, dataUri: string): string {
// Skip caching entries that alone exceed the byte budget. Caching them
// would trigger immediate self-eviction on insert and pollute LRU order
@@ -188,6 +189,7 @@ export function createVideoFrameInjector(
const frameCache = createFrameSourceCache(entryLimit, bytesLimit, config?.frameSrcResolver);
const lastInjectedFrameByVideo = new Map<string, number>();
// fallow-ignore-next-line complexity
return async (page: Page, time: number) => {
const activePayloads = frameLookup.getActiveFramePayloads(time);
@@ -275,47 +277,43 @@ export interface VideoElementBounds {
* holes where the HDR videos go.
*/
export async function hideVideoElements(page: Page, videoIds: string[]): Promise<void> {
if (videoIds.length === 0) return;
await page.evaluate(
(ids: string[], canvasIdPrefix: string) => {
for (const id of ids) {
const el = document.getElementById(id) as HTMLVideoElement | null;
if (el) {
el.style.setProperty("visibility", "hidden", "important");
const img = document.getElementById(`__render_frame_${id}__`);
if (img) img.style.setProperty("visibility", "hidden", "important");
const colorGradingCanvas = document.getElementById(`${canvasIdPrefix}${id}`);
if (colorGradingCanvas) {
colorGradingCanvas.style.setProperty("visibility", "hidden", "important");
}
}
}
},
videoIds,
HF_COLOR_GRADING_CANVAS_ID_PREFIX,
);
await setVideoElementsVisibility(page, videoIds, false);
}
/**
* Restore visibility of video elements after a DOM screenshot.
*/
export async function showVideoElements(page: Page, videoIds: string[]): Promise<void> {
await setVideoElementsVisibility(page, videoIds, true);
}
async function setVideoElementsVisibility(
page: Page,
videoIds: string[],
visible: boolean,
): Promise<void> {
if (videoIds.length === 0) return;
await page.evaluate(
(ids: string[], canvasIdPrefix: string) => {
for (const id of ids) {
const el = document.getElementById(id) as HTMLVideoElement | null;
if (el) {
el.style.removeProperty("visibility");
const img = document.getElementById(`__render_frame_${id}__`);
if (img) img.style.removeProperty("visibility");
const colorGradingCanvas = document.getElementById(`${canvasIdPrefix}${id}`);
if (colorGradingCanvas) colorGradingCanvas.style.removeProperty("visibility");
(ids: string[], canvasIdPrefix: string, shouldShow: boolean) => {
const apply = (node: Element | null) => {
if (!(node instanceof HTMLElement)) return;
if (shouldShow) {
node.style.removeProperty("visibility");
} else {
node.style.setProperty("visibility", "hidden", "important");
}
};
for (const id of ids) {
const video = document.getElementById(id);
if (!video) continue;
apply(video);
apply(document.getElementById(`__render_frame_${id}__`));
apply(document.getElementById(`${canvasIdPrefix}${id}`));
}
},
videoIds,
HF_COLOR_GRADING_CANVAS_ID_PREFIX,
visible,
);
}
@@ -431,6 +429,7 @@ export async function queryElementStacking(
nativeHdrIds: Set<string>,
): Promise<ElementStackingInfo[]> {
const hdrIds = Array.from(nativeHdrIds);
// fallow-ignore-next-line complexity
return page.evaluate((hdrIdList: string[]): ElementStackingInfo[] => {
const hdrSet = new Set(hdrIdList);
const elements = document.querySelectorAll("[data-start]");
@@ -470,6 +469,7 @@ export async function queryElementStacking(
// Find border-radius that clips the element. Replaced elements like <video>
// clip to their own border-radius; ancestors need overflow !== visible.
// fallow-ignore-next-line complexity
function getEffectiveBorderRadius(node: Element): [number, number, number, number] {
// Resolve a CSS border-radius value to pixels. Chrome's getComputedStyle
// returns percentages as-is (e.g. "50%"), not resolved to px.
@@ -572,6 +572,7 @@ export async function queryElementStacking(
// position offsets + CSS transforms. This correctly handles GSAP
// animations on wrapper divs (rotation, scale) that getBoundingClientRect
// conflates into an axis-aligned bounding box.
// fallow-ignore-next-line complexity
function getViewportMatrix(node: Element): string {
const chain: HTMLElement[] = [];
let current: Element | null = node;
@@ -620,6 +621,7 @@ export async function queryElementStacking(
return mat.toString();
}
// fallow-ignore-next-line complexity
function composeIndividualTransforms(cs: CSSStyleDeclaration): DOMMatrix | null {
const translate = cs.getPropertyValue("translate").trim();
const rotate = cs.getPropertyValue("rotate").trim();