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);
|
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());
|
||||||
|
Reference in New Issue
Block a user