GenericHighlighter: check text color against background

The kate syntax highlighter format allows to directly assign a color for
a specific item. This could result in a bad contrast ratio between text
and background. Check the contrast ratio according to W3C Recommendation
and apply if it exceeds the minimum contrast ratio for large text.
(https://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-
contrast)

Task-number: QTCREATORBUG-20919
Change-Id: If5a5d09224446df72f31027cd30e50088179d6d7
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2018-08-14 06:55:56 +02:00
parent cfbc780a20
commit 493c5396ff

View File

@@ -498,6 +498,43 @@ void Highlighter::handleContextChange(const QString &contextName,
changeContext(contextName, definition, setCurrent); changeContext(contextName, definition, setCurrent);
} }
static double luminance(const QColor &color)
{
// calculate the luminance based on
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
auto val = [](const double &colorVal) {
return colorVal < 0.03928 ? colorVal / 12.92 : std::pow((colorVal + 0.055) / 1.055, 2.4);
};
static QHash<QRgb, double> cache;
QHash<QRgb, double>::iterator it = cache.find(color.rgb());
if (it == cache.end()) {
it = cache.insert(color.rgb(), 0.2126 * val(color.redF())
+ 0.7152 * val(color.greenF())
+ 0.0722 * val(color.blueF()));
}
return it.value();
}
static float contrastRatio(const QColor &color1, const QColor &color2)
{
// calculate the contrast ratio based on
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
auto contrast = (luminance(color1) + 0.05) / (luminance(color2) + 0.05);
if (contrast < 1)
return 1 / contrast;
return contrast;
}
static bool isReadableOn(const QColor &background, const QColor &foreground)
{
// following the W3C Recommendation on contrast for large Text
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
return contrastRatio(background, foreground) > 3;
}
void Highlighter::applyFormat(int offset, void Highlighter::applyFormat(int offset,
int count, int count,
const QString &itemDataName, const QString &itemDataName,
@@ -526,7 +563,10 @@ void Highlighter::applyFormat(int offset,
// strategy). This is because the highlighter does not really know on which // strategy). This is because the highlighter does not really know on which
// definition(s) it is working. Since not many item data specify customizations I // definition(s) it is working. Since not many item data specify customizations I
// think this approach would fit better. If there are other ideas... // think this approach would fit better. If there are other ideas...
if (itemData->color().isValid()) QBrush bg = format.background();
if (bg.style() == Qt::NoBrush)
bg = formatForCategory(C_TEXT).background();
if (itemData->color().isValid() && isReadableOn(bg.color(), itemData->color()))
format.setForeground(itemData->color()); format.setForeground(itemData->color());
if (itemData->isItalicSpecified()) if (itemData->isItalicSpecified())
format.setFontItalic(itemData->isItalic()); format.setFontItalic(itemData->isItalic());