forked from qt-creator/qt-creator
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:
@@ -498,6 +498,43 @@ void Highlighter::handleContextChange(const QString &contextName,
|
||||
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,
|
||||
int count,
|
||||
const QString &itemDataName,
|
||||
@@ -526,7 +563,10 @@ void Highlighter::applyFormat(int offset,
|
||||
// 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
|
||||
// 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());
|
||||
if (itemData->isItalicSpecified())
|
||||
format.setFontItalic(itemData->isItalic());
|
||||
|
Reference in New Issue
Block a user