mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(cli): consolidate layout and contrast audit correctness (#2401)
* fix(cli): respect transparent image pixels in occlusion audit * test(cli): cover contained image letterboxing * fix(cli): account for text strokes in contrast checks * fix(cli): honor text overflow opt-outs * fix(cli): skip contrast on transparent backdrops * chore(skills): refresh generated manifest
This commit is contained in:
@@ -220,6 +220,9 @@ window.__contrastAuditPrepare = function () {
|
||||
var isSvgText = isSvgTextElement(el);
|
||||
var fg = isSvgText ? tryParseSolidColor(cs.fill) || parseColor(cs.color) : parseColor(cs.color);
|
||||
if (fg[3] <= 0.01) continue;
|
||||
var strokeWidth = parseFloat(cs.webkitTextStrokeWidth || "0");
|
||||
var stroke = strokeWidth > 0 ? tryParseSolidColor(cs.webkitTextStrokeColor || "") : null;
|
||||
if (stroke && stroke[3] <= 0.01) stroke = null;
|
||||
|
||||
var fontSize = parseFloat(cs.fontSize);
|
||||
var fontWeight = Number(cs.fontWeight) || 400;
|
||||
@@ -251,6 +254,13 @@ window.__contrastAuditPrepare = function () {
|
||||
origFillPriority = el.style.getPropertyPriority("fill");
|
||||
el.style.setProperty("fill", "transparent", "important");
|
||||
}
|
||||
var origStrokeColor = null,
|
||||
origStrokeColorPriority = null;
|
||||
if (stroke) {
|
||||
origStrokeColor = el.style.getPropertyValue("-webkit-text-stroke-color");
|
||||
origStrokeColorPriority = el.style.getPropertyPriority("-webkit-text-stroke-color");
|
||||
el.style.setProperty("-webkit-text-stroke-color", "transparent", "important");
|
||||
}
|
||||
restores.push({
|
||||
el: el,
|
||||
origTransition: origTransition,
|
||||
@@ -259,6 +269,9 @@ window.__contrastAuditPrepare = function () {
|
||||
origColorPriority: origColorPriority,
|
||||
origFill: origFill,
|
||||
origFillPriority: origFillPriority,
|
||||
origStrokeColor: origStrokeColor,
|
||||
origStrokeColorPriority: origStrokeColorPriority,
|
||||
hasStroke: !!stroke,
|
||||
isSvgText: isSvgText,
|
||||
});
|
||||
|
||||
@@ -266,6 +279,7 @@ window.__contrastAuditPrepare = function () {
|
||||
selector: selectorOf(el),
|
||||
text: (el.textContent || "").trim().slice(0, 50),
|
||||
fg: fg,
|
||||
stroke: stroke,
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
large: large,
|
||||
@@ -287,6 +301,15 @@ function __contrastAuditRestoreAll() {
|
||||
if (r.origFill) r.el.style.setProperty("fill", r.origFill, r.origFillPriority);
|
||||
else r.el.style.removeProperty("fill");
|
||||
}
|
||||
if (r.hasStroke) {
|
||||
if (r.origStrokeColor)
|
||||
r.el.style.setProperty(
|
||||
"-webkit-text-stroke-color",
|
||||
r.origStrokeColor,
|
||||
r.origStrokeColorPriority,
|
||||
);
|
||||
else r.el.style.removeProperty("-webkit-text-stroke-color");
|
||||
}
|
||||
if (r.origTransition)
|
||||
r.el.style.setProperty("transition", r.origTransition, r.origTransitionPriority);
|
||||
else r.el.style.removeProperty("transition");
|
||||
@@ -371,17 +394,25 @@ window.__contrastAuditFinish = async function (imgBase64, time, candidates) {
|
||||
var stepY = Math.max(1, Math.floor((y1 - y0) / 6));
|
||||
var rr = [],
|
||||
gg = [],
|
||||
bb = [];
|
||||
bb = [],
|
||||
aa = [];
|
||||
for (var y = y0; y <= y1; y += stepY) {
|
||||
for (var x = x0; x <= x1; x += stepX) {
|
||||
var idx = (y * w + x) * 4;
|
||||
rr.push(px[idx]);
|
||||
gg.push(px[idx + 1]);
|
||||
bb.push(px[idx + 2]);
|
||||
aa.push(px[idx + 3]);
|
||||
}
|
||||
}
|
||||
if (rr.length === 0) continue;
|
||||
|
||||
// A transparent sampled backdrop is supplied by the downstream editor,
|
||||
// not this composition. WCAG contrast cannot be inferred until that live
|
||||
// video/image is known, so do not invent an opaque browser default and
|
||||
// hard-fail an otherwise valid alpha overlay.
|
||||
if (median(aa) < 255) continue;
|
||||
|
||||
var bgR = median(rr),
|
||||
bgG = median(gg),
|
||||
bgB = median(bb);
|
||||
@@ -394,6 +425,23 @@ window.__contrastAuditFinish = async function (imgBase64, time, candidates) {
|
||||
|
||||
var ratio = +wcagRatio(compR, compG, compB, bgR, bgG, bgB).toFixed(2);
|
||||
|
||||
// A solid text stroke is part of the visible glyph paint. Use whichever
|
||||
// of fill or stroke provides the stronger edge contrast, rather than
|
||||
// failing readable outlined captions based on fill alone.
|
||||
if (c.stroke) {
|
||||
var stroke = c.stroke;
|
||||
var strokeR = Math.round(stroke[0] * stroke[3] + bgR * (1 - stroke[3]));
|
||||
var strokeG = Math.round(stroke[1] * stroke[3] + bgG * (1 - stroke[3]));
|
||||
var strokeB = Math.round(stroke[2] * stroke[3] + bgB * (1 - stroke[3]));
|
||||
var strokeRatio = +wcagRatio(strokeR, strokeG, strokeB, bgR, bgG, bgB).toFixed(2);
|
||||
if (strokeRatio > ratio) {
|
||||
compR = strokeR;
|
||||
compG = strokeG;
|
||||
compB = strokeB;
|
||||
ratio = strokeRatio;
|
||||
}
|
||||
}
|
||||
|
||||
out.push({
|
||||
time: time,
|
||||
selector: c.selector,
|
||||
|
||||
Reference in New Issue
Block a user