This commit is contained in:
Josh at WLTechBlog
2025-12-09 13:48:27 -07:00
parent 6ad3d6e40e
commit 6b26c13add
2 changed files with 137 additions and 47 deletions

View File

@@ -9149,57 +9149,62 @@ func (d *Daemon) checkContrast(tabID string, selector string, timeout int) (*Con
}
}
// Tier 3: Gradient analysis
// Tier 3: Gradient analysis - walks up DOM tree to find gradient backgrounds
function analyzeGradientContrast(element, textColor) {
try {
const style = window.getComputedStyle(element);
const bgImage = style.backgroundImage;
// Walk up the DOM tree to find a gradient background
let current = element;
while (current && current !== document.documentElement.parentElement) {
const style = window.getComputedStyle(current);
const bgImage = style.backgroundImage;
// Check if background is a gradient
if (!bgImage || !bgImage.includes('gradient')) {
return null;
}
// Check if background is a gradient
if (bgImage && bgImage.includes('gradient')) {
// Extract gradient colors using regex
const colorRegex = /rgba?\([^)]+\)|#[0-9a-f]{3,6}/gi;
const matches = bgImage.match(colorRegex) || [];
// Fix incomplete rgb/rgba matches by adding closing paren
const colors = matches.map(c => c.includes('(') && !c.includes(')') ? c + ')' : c);
// Extract gradient colors using regex
const colorRegex = /rgba?\([^)]+\)|#[0-9a-f]{3,6}/gi;
const matches = bgImage.match(colorRegex) || [];
// Fix incomplete rgb/rgba matches by adding closing paren
const colors = matches.map(c => c.includes('(') && !c.includes(')') ? c + ')' : c);
if (colors.length > 0) {
// Calculate contrast against each color in the gradient
const fg = parseColor(textColor);
if (!fg) {
current = current.parentElement;
continue;
}
if (colors.length === 0) {
return null;
}
const contrastRatios = [];
const parsedColors = [];
// Calculate contrast against each color in the gradient
const fg = parseColor(textColor);
if (!fg) return null;
for (const colorStr of colors) {
const bg = parseColor(colorStr);
if (bg) {
const ratio = getContrastRatio(fg, bg);
contrastRatios.push(ratio);
parsedColors.push(colorStr);
}
}
const contrastRatios = [];
const parsedColors = [];
if (contrastRatios.length > 0) {
// Return worst-case (minimum) contrast ratio
const worstCase = Math.min(...contrastRatios);
const bestCase = Math.max(...contrastRatios);
for (const colorStr of colors) {
const bg = parseColor(colorStr);
if (bg) {
const ratio = getContrastRatio(fg, bg);
contrastRatios.push(ratio);
parsedColors.push(colorStr);
return {
worstCase: worstCase,
bestCase: bestCase,
colors: parsedColors,
isGradient: true
};
}
}
}
current = current.parentElement;
}
if (contrastRatios.length === 0) {
return null;
}
// Return worst-case (minimum) contrast ratio
const worstCase = Math.min(...contrastRatios);
const bestCase = Math.max(...contrastRatios);
return {
worstCase: worstCase,
bestCase: bestCase,
colors: parsedColors,
isGradient: true
};
return null;
} catch (e) {
return null;
}
@@ -9293,7 +9298,7 @@ func (d *Daemon) checkContrast(tabID string, selector string, timeout int) (*Con
let detectionMethod = null;
let gradientInfo = null;
// Tier 1: DOM tree walking
// Tier 1: DOM tree walking for solid colors
bgColor = getEffectiveBackgroundDOMTree(element);
if (bgColor) {
detectionMethod = 'dom-tree';
@@ -9307,12 +9312,14 @@ func (d *Daemon) checkContrast(tabID string, selector string, timeout int) (*Con
}
}
// Tier 3: Check for gradient backgrounds
if (bgColor) {
gradientInfo = analyzeGradientContrast(element, fgColor);
if (gradientInfo) {
detectionMethod = 'gradient-analysis';
}
// Tier 3: Check for gradient backgrounds (always check, even if solid color found)
// Gradients take precedence over solid colors when present
gradientInfo = analyzeGradientContrast(element, fgColor);
if (gradientInfo) {
detectionMethod = 'gradient-analysis';
// Use a representative color from the gradient for the background_color field
// We'll use the worst-case color for reporting purposes
bgColor = gradientInfo.colors[0] || bgColor;
}
// Final fallback to white if no background detected