From de03391c2d6bc1eb3b66c56e838ec8968b85cad8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 May 2022 11:19:38 -0700 Subject: [PATCH] Allow ensureContrastRatio to change luminance the other way The higher ratio of the two results will be picked. Fixes #3720 --- src/common/Color.ts | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/common/Color.ts b/src/common/Color.ts index b197cd66af..a2a3cbad00 100644 --- a/src/common/Color.ts +++ b/src/common/Color.ts @@ -150,15 +150,42 @@ export namespace rgb { * Helper functions where the source type is "rgba" (number: 0xrrggbbaa). */ export namespace rgba { + /** + * Given a foreground color and a background color, either increase or reduce the luminance of the + * foreground color until the specified contrast ratio is met. If pure white or black is hit + * without the contrast ratio being met, go the other direction using the background color as the + * foreground color and take either the first or second result depending on which has the higher + * contrast ratio. + * + * `undefined` will be returned if the contrast ratio is already met. + * + * @param bgRgba The background color in rgba format. + * @param fgRgba The foreground color in rgba format. + * @param ratio The contrast ratio to achieve. + */ export function ensureContrastRatio(bgRgba: number, fgRgba: number, ratio: number): number | undefined { const bgL = rgb.relativeLuminance(bgRgba >> 8); const fgL = rgb.relativeLuminance(fgRgba >> 8); const cr = contrastRatio(bgL, fgL); if (cr < ratio) { if (fgL < bgL) { - return reduceLuminance(bgRgba, fgRgba, ratio); + const resultA = reduceLuminance(bgRgba, fgRgba, ratio); + const resultARatio = contrastRatio(bgL, rgb.relativeLuminance(resultA >> 8)); + if (resultARatio < ratio) { + const resultB = increaseLuminance(bgRgba, bgRgba, ratio); + const resultBRatio = contrastRatio(bgL, rgb.relativeLuminance(resultB >> 8)); + return resultARatio > resultBRatio ? resultA : resultB; + } + return resultA; + } + const resultA = increaseLuminance(bgRgba, fgRgba, ratio); + const resultARatio = contrastRatio(bgL, rgb.relativeLuminance(resultA >> 8)); + if (resultARatio < ratio) { + const resultB = reduceLuminance(bgRgba, bgRgba, ratio); + const resultBRatio = contrastRatio(bgL, rgb.relativeLuminance(resultB >> 8)); + return resultARatio > resultBRatio ? resultA : resultB; } - return increaseLuminance(bgRgba, fgRgba, ratio); + return resultA; } return undefined; }