[Libreoffice-commits] core.git: sw/source

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Sat Dec 28 11:37:28 UTC 2019


 sw/source/core/access/AccessibilityCheck.cxx |  134 +++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

New commits:
commit cfa594ad0dd7f8e464d8d59f49184a687b1503dc
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 10:51:39 2019 +0100
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Sat Dec 28 12:36:53 2019 +0100

    acc. check: text vs. background contrast check
    
    Contrast between text and background shouldn't be too low (under
    4.5). The way how to calculate the contrast is defined by the
    WCAG21.
    
    Change-Id: Ic52ab68ba0ec6a4ab58e6b01afe74e8e7eeae104
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/85905
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index 5608e29dff47..5143ddfb6887 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -23,6 +23,8 @@
 #include <tools/urlobj.hxx>
 #include <editeng/langitem.hxx>
 #include <charatr.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
 
 namespace sw
 {
@@ -36,6 +38,7 @@ OUString sHyperlinkTextIsLink("Hyperlink text is the same as the link address '%
 OUString sDocumentDefaultLanguage("Document default language is not set");
 OUString sStyleNoLanguage("Style '%STYLE_NAME%' has no language set");
 OUString sDocumentTitle("Document title is not set");
+OUString sTextContrast("Text contrast is too low.");
 
 class BaseCheck
 {
@@ -260,6 +263,136 @@ public:
     }
 };
 
+// Based on https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
+double calculateRelativeLuminance(Color const& rColor)
+{
+    // Convert to BColor which has R, G, B colors components
+    // represented by a floating point number from [0.0, 1.0]
+    const basegfx::BColor aBColor = rColor.getBColor();
+
+    double r = aBColor.getRed();
+    double g = aBColor.getGreen();
+    double b = aBColor.getBlue();
+
+    // Calculate the values according to the described algorithm
+    r = (r <= 0.03928) ? r / 12.92 : std::pow((r + 0.055) / 1.055, 2.4);
+    g = (g <= 0.03928) ? g / 12.92 : std::pow((g + 0.055) / 1.055, 2.4);
+    b = (b <= 0.03928) ? b / 12.92 : std::pow((b + 0.055) / 1.055, 2.4);
+
+    return 0.2126 * r + 0.7152 * g + 0.0722 * b;
+}
+
+// TODO move to common color tools (BColorTools maybe)
+// Based on https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
+double calculateContrastRatio(Color const& rColor1, Color const& rColor2)
+{
+    const double fLuminance1 = calculateRelativeLuminance(rColor1);
+    const double fLuminance2 = calculateRelativeLuminance(rColor2);
+    const std::pair<const double, const double> aMinMax = std::minmax(fLuminance1, fLuminance2);
+
+    // (L1 + 0.05) / (L2 + 0.05)
+    // L1 is the lighter color (greater luminance value)
+    // L2 is the darker color (smaller luminance value)
+    return (aMinMax.second + 0.05) / (aMinMax.first + 0.05);
+}
+
+class TextContrastCheck : public NodeCheck
+{
+private:
+    void checkTextRange(uno::Reference<text::XTextRange> const& xTextRange,
+                        uno::Reference<text::XTextContent> const& xParagraph, SwTextNode* pTextNode)
+    {
+        sal_Int32 nParaBackColor;
+        uno::Reference<beans::XPropertySet> xParagraphProperties(xParagraph, uno::UNO_QUERY);
+        xParagraphProperties->getPropertyValue("ParaBackColor") >>= nParaBackColor;
+
+        uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
+        if (xProperties.is())
+        {
+            // Forground color
+            sal_Int32 nCharColor;
+            xProperties->getPropertyValue("CharColor") >>= nCharColor;
+            Color aForegroundColor(nCharColor);
+            if (aForegroundColor == COL_AUTO)
+                return;
+
+            const SwPageDesc* pPageDescription = pTextNode->FindPageDesc();
+            const SwFrameFormat& rPageFormat = pPageDescription->GetMaster();
+            const SwAttrSet& rPageSet = rPageFormat.GetAttrSet();
+
+            const XFillStyleItem* pXFillStyleItem(
+                rPageSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE, false));
+            Color aPageBackground;
+
+            if (pXFillStyleItem->GetValue() == css::drawing::FillStyle_SOLID)
+            {
+                const XFillColorItem* rXFillColorItem
+                    = rPageSet.GetItem<XFillColorItem>(XATTR_FILLCOLOR, false);
+                aPageBackground = rXFillColorItem->GetColorValue();
+            }
+
+            sal_Int32 nCharBackColor;
+            sal_Int16 eRelief;
+
+            xProperties->getPropertyValue("CharBackColor") >>= nCharBackColor;
+            xProperties->getPropertyValue("CharRelief") >>= eRelief;
+
+            // Determine the background color
+            // Try Character background (highlight)
+            Color aBackgroundColor(nCharBackColor);
+
+            // If not character background color, try paragraph background color
+            if (aBackgroundColor == COL_AUTO)
+                aBackgroundColor = Color(nParaBackColor);
+
+            // If not paragraph background color, try page color
+            if (aBackgroundColor == COL_AUTO)
+                aBackgroundColor = aPageBackground;
+
+            // If not page color, assume white background color
+            if (aBackgroundColor == COL_AUTO)
+                aBackgroundColor = COL_WHITE;
+
+            double fContrastRatio = calculateContrastRatio(aForegroundColor, aBackgroundColor);
+            if (fContrastRatio < 4.5)
+            {
+                svx::AccessibilityIssue aIssue;
+                aIssue.m_aIssueText = sTextContrast;
+                m_rIssueCollection.push_back(aIssue);
+            }
+        }
+    }
+
+public:
+    TextContrastCheck(std::vector<svx::AccessibilityIssue>& rIssueCollection)
+        : NodeCheck(rIssueCollection)
+    {
+    }
+
+    void check(SwNode* pCurrent) override
+    {
+        if (pCurrent->IsTextNode())
+        {
+            SwTextNode* pTextNode = pCurrent->GetTextNode();
+            uno::Reference<text::XTextContent> xParagraph;
+            xParagraph = SwXParagraph::CreateXParagraph(*pTextNode->GetDoc(), pTextNode);
+            if (xParagraph.is())
+            {
+                uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph,
+                                                                             uno::UNO_QUERY);
+                uno::Reference<container::XEnumeration> xRunEnum
+                    = xRunEnumAccess->createEnumeration();
+                while (xRunEnum->hasMoreElements())
+                {
+                    uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
+                    if (xRun.is())
+                        checkTextRange(xRun, xParagraph, pTextNode);
+                }
+            }
+        }
+    }
+};
+
 class DocumentCheck : public BaseCheck
 {
 public:
@@ -376,6 +509,7 @@ void AccessibilityCheck::check()
     aNodeChecks.push_back(std::make_unique<TableNodeMergeSplitCheck>(m_aIssueCollection));
     aNodeChecks.push_back(std::make_unique<NumberingCheck>(m_aIssueCollection));
     aNodeChecks.push_back(std::make_unique<HyperlinkCheck>(m_aIssueCollection));
+    aNodeChecks.push_back(std::make_unique<TextContrastCheck>(m_aIssueCollection));
 
     auto const& pNodes = m_pDoc->GetNodes();
     SwNode* pNode = nullptr;


More information about the Libreoffice-commits mailing list