11 #include <AccessibilityCheck.hxx>
12 #include <AccessibilityIssue.hxx>
13 #include <AccessibilityCheckStrings.hrc>
18 #include <drawdoc.hxx>
21 #include <com/sun/star/frame/XModel.hpp>
22 #include <com/sun/star/text/XTextContent.hpp>
23 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
44 std::shared_ptr<sw::AccessibilityIssue>
48 auto pIssue = std::make_shared<sw::AccessibilityIssue>(eIssue);
49 pIssue->m_aIssueText = rText;
50 rIssueCollection.
getIssues().push_back(pIssue);
61 : m_rIssueCollection(rIssueCollection)
64 virtual ~BaseCheck() {}
67 class NodeCheck :
public BaseCheck
71 : BaseCheck(rIssueCollection)
79 class NoTextNodeAltTextCheck :
public NodeCheck
86 OUString sAlternative = pNoTextNode->
GetTitle();
87 if (!sAlternative.isEmpty())
92 OUString sIssueText =
SwResId(STR_NO_ALT).replaceAll(
"%OBJECT_NAME%", sName);
98 pIssue->setDoc(pNoTextNode->
GetDoc());
106 pIssue->setDoc(pNoTextNode->
GetDoc());
114 : NodeCheck(rIssueCollection)
124 checkNoTextNode(pNoTextNode);
130 class TableNodeMergeSplitCheck :
public NodeCheck
136 OUString sName = pFormat->
GetName();
137 OUString sIssueText =
SwResId(STR_TABLE_MERGE_SPLIT).replaceAll(
"%OBJECT_NAME%", sName);
140 pIssue->setDoc(rDoc);
142 pIssue->setObjectID(sName);
154 addTableIssue(rTable, rDoc);
161 size_t nFirstLineSize = 0;
162 bool bAllColumnsSameSize =
true;
163 bool bCellSpansOverMoreRows =
false;
169 nFirstLineSize = pTableLine->GetTabBoxes().size();
173 size_t nLineSize = pTableLine->GetTabBoxes().size();
174 if (nFirstLineSize != nLineSize)
176 bAllColumnsSameSize =
false;
182 for (
SwTableBox const* pBox : pTableLine->GetTabBoxes())
184 if (pBox->getRowSpan() > 1)
185 bCellSpansOverMoreRows =
true;
188 if (!bAllColumnsSameSize || bCellSpansOverMoreRows)
190 addTableIssue(rTable, rDoc);
198 : NodeCheck(rIssueCollection)
208 checkTableNode(pTableNode);
213 class NumberingCheck :
public NodeCheck
219 {
"1.",
"2." }, {
"(1)",
"(2)" }, {
"1)",
"2)" }, {
"a.",
"b." }, {
"(a)",
"(b)" },
220 {
"a)",
"b)" }, {
"A.",
"B." }, {
"(A)",
"(B)" }, {
"A)",
"B)" }
225 : NodeCheck(rIssueCollection)
226 , m_pPreviousTextNode(nullptr)
235 if (m_pPreviousTextNode)
240 && m_pPreviousTextNode->
GetText().startsWith(rPair.first))
242 OUString sNumbering = rPair.first +
" " + rPair.second +
"...";
244 =
SwResId(STR_FAKE_NUMBERING).replaceAll(
"%NUMBERING%", sNumbering);
253 class HyperlinkCheck :
public NodeCheck
256 void checkTextRange(uno::Reference<text::XTextRange>
const& xTextRange)
258 uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
259 if (!xProperties->getPropertySetInfo()->hasPropertyByName(
"HyperLinkURL"))
263 xProperties->getPropertyValue(
"HyperLinkURL") >>= sHyperlink;
264 if (!sHyperlink.isEmpty())
266 OUString sText = xTextRange->getString();
270 =
SwResId(STR_HYPERLINK_TEXT_IS_LINK).replaceFirst(
"%LINK%", sHyperlink);
278 : NodeCheck(rIssueCollection)
288 uno::Reference<text::XTextContent> xParagraph
290 if (!xParagraph.is())
293 uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
294 uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
295 while (xRunEnum->hasMoreElements())
297 uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
300 checkTextRange(xRun);
307 double calculateRelativeLuminance(
Color const& rColor)
313 double r = aBColor.
getRed();
318 r = (r <= 0.03928) ? r / 12.92 : std::pow((r + 0.055) / 1.055, 2.4);
319 g = (g <= 0.03928) ? g / 12.92 : std::pow((g + 0.055) / 1.055, 2.4);
320 b = (b <= 0.03928) ? b / 12.92 : std::pow((b + 0.055) / 1.055, 2.4);
322 return 0.2126 * r + 0.7152 * g + 0.0722 * b;
327 double calculateContrastRatio(
Color const& rColor1,
Color const& rColor2)
329 const double fLuminance1 = calculateRelativeLuminance(rColor1);
330 const double fLuminance2 = calculateRelativeLuminance(rColor2);
331 const std::pair<const double, const double> aMinMax = std::minmax(fLuminance1, fLuminance2);
336 return (aMinMax.second + 0.05) / (aMinMax.first + 0.05);
339 class TextContrastCheck :
public NodeCheck
342 void checkTextRange(uno::Reference<text::XTextRange>
const& xTextRange,
343 uno::Reference<text::XTextContent>
const& xParagraph,
346 Color nParaBackColor(COL_AUTO);
347 uno::Reference<beans::XPropertySet> xParagraphProperties(xParagraph, uno::UNO_QUERY);
348 if (!(xParagraphProperties->getPropertyValue(
"ParaBackColor") >>= nParaBackColor))
350 SAL_WARN(
"sw.a11y",
"ParaBackColor void");
354 uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
355 if (!xProperties.is())
359 sal_Int32 nCharColor = {};
360 if (!(xProperties->getPropertyValue(
"CharColor") >>= nCharColor))
362 SAL_WARN(
"sw.a11y",
"CharColor void");
365 Color aForegroundColor(ColorTransparency, nCharColor);
366 if (aForegroundColor == COL_AUTO)
375 Color aPageBackground(COL_AUTO);
377 if (pXFillStyleItem && pXFillStyleItem->GetValue() == css::drawing::FillStyle_SOLID)
384 Color nCharBackColor(COL_AUTO);
386 if (!(xProperties->getPropertyValue(
"CharBackColor") >>= nCharBackColor))
388 SAL_WARN(
"sw.a11y",
"CharBackColor void");
393 Color aBackgroundColor(nCharBackColor);
396 if (aBackgroundColor == COL_AUTO)
397 aBackgroundColor = nParaBackColor;
400 if (aBackgroundColor == COL_AUTO)
401 aBackgroundColor = aPageBackground;
404 if (aBackgroundColor == COL_AUTO)
407 double fContrastRatio = calculateContrastRatio(aForegroundColor, aBackgroundColor);
408 if (fContrastRatio < 4.5)
416 : NodeCheck(rIssueCollection)
426 uno::Reference<text::XTextContent> xParagraph;
428 if (!xParagraph.is())
431 uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
432 uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
433 while (xRunEnum->hasMoreElements())
435 uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
437 checkTextRange(xRun, xParagraph, pTextNode);
442 class TextFormattingCheck :
public NodeCheck
447 : NodeCheck(rIssueCollection)
456 std::vector<OUString> aFormattings;
459 OUString sFormattingType;
460 switch (pItem->Which())
465 sFormattingType =
"Weight";
470 sFormattingType =
"Posture";
474 sFormattingType =
"Shadowed";
478 sFormattingType =
"Font Color";
484 sFormattingType =
"Font Size";
490 sFormattingType =
"Font";
494 sFormattingType =
"Emphasis Mark";
498 sFormattingType =
"Underline";
502 sFormattingType =
"Overline";
506 sFormattingType =
"Strikethrough";
510 sFormattingType =
"Relief";
514 sFormattingType =
"Outline";
519 if (!sFormattingType.isEmpty())
520 aFormattings.push_back(sFormattingType);
521 pItem = aItemIter.NextItem();
523 if (aFormattings.empty())
530 pIssue->setNode(pTextNode);
532 pIssue->setDoc(rDocument);
533 pIssue->setStart(pTextAttr->
GetStart());
545 for (
size_t i = 0; i < rHints.
Count(); ++i)
550 checkAutoFormat(pTextNode, pTextAttr);
557 class BlinkingTextCheck :
public NodeCheck
560 void checkTextRange(uno::Reference<text::XTextRange>
const& xTextRange)
562 uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
563 if (xProperties.is() && xProperties->getPropertySetInfo()->hasPropertyByName(
"CharFlash"))
565 bool bBlinking =
false;
566 xProperties->getPropertyValue(
"CharFlash") >>= bBlinking;
577 : NodeCheck(rIssueCollection)
587 uno::Reference<text::XTextContent> xParagraph;
589 if (!xParagraph.is())
592 uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
593 uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
594 while (xRunEnum->hasMoreElements())
596 uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
598 checkTextRange(xRun);
603 class HeaderCheck :
public NodeCheck
610 : NodeCheck(rIssueCollection)
611 , m_nPreviousLevel(0)
626 if (nLevel > m_nPreviousLevel && std::abs(nLevel - m_nPreviousLevel) > 1)
630 m_nPreviousLevel = nLevel;
635 class NonInteractiveFormCheck :
public NodeCheck
639 : NodeCheck(rIssueCollection)
652 bool bCheck =
text.indexOf(
"___") == -1;
655 bCheck =
text.indexOf(
"....") == -1;
658 bCheck =
text.indexOf(u
"……") == -1;
661 bCheck =
text.indexOf(u
"….") == -1;
664 bCheck =
text.indexOf(u
".…") == -1;
673 class FloatingTextCheck :
public NodeCheck
677 : NodeCheck(rIssueCollection)
685 if (!textNode || textNode->
GetText().isEmpty())
697 class TableHeadingCheck :
public NodeCheck
705 : NodeCheck(rIssueCollection)
706 , m_bPrevPassed(true)
723 m_bPrevPassed =
false;
731 class HeadingOrderCheck :
public NodeCheck
735 : NodeCheck(rIssueCollection)
753 OUString resultString =
SwResId(STR_HEADING_ORDER);
755 = resultString.replaceAll(
"%LEVEL_CURRENT%", OUString::number(currentLevel));
757 = resultString.replaceAll(
"%LEVEL_PREV%", OUString::number(
m_prevLevel));
772 class DocumentCheck :
public BaseCheck
776 : BaseCheck(rIssueCollection)
784 class DocumentDefaultLanguageCheck :
public DocumentCheck
788 : DocumentCheck(rIssueCollection)
797 if (eLanguage == LANGUAGE_NONE)
806 const SwAttrSet& rAttrSet = pTextFormatCollection->GetAttrSet();
809 OUString sName = pTextFormatCollection->GetName();
811 =
SwResId(STR_STYLE_NO_LANGUAGE).replaceAll(
"%STYLE_NAME%", sName);
820 class DocumentTitleCheck :
public DocumentCheck
824 : DocumentCheck(rIssueCollection)
834 const uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pShell->
GetModel(),
835 uno::UNO_QUERY_THROW);
836 const uno::Reference<document::XDocumentProperties> xDocumentProperties(
837 xDPS->getDocumentProperties());
838 OUString sTitle = xDocumentProperties->getTitle();
839 if (sTitle.isEmpty())
847 class FootnoteEndnoteCheck :
public DocumentCheck
851 : DocumentCheck(rIssueCollection)
887 if (pAny->get<OUString>().startsWith(
"fontwork-"))
899 OUString sAlternative = pObject->
GetTitle();
900 if (sAlternative.isEmpty())
902 OUString sName = pObject->
GetName();
903 OUString sIssueText =
SwResId(STR_NO_ALT).replaceAll(
"%OBJECT_NAME%", sName);
914 std::vector<std::unique_ptr<DocumentCheck>> aDocumentChecks;
915 aDocumentChecks.push_back(std::make_unique<DocumentDefaultLanguageCheck>(
m_aIssueCollection));
917 aDocumentChecks.push_back(std::make_unique<FootnoteEndnoteCheck>(
m_aIssueCollection));
919 for (std::unique_ptr<DocumentCheck>& rpDocumentCheck : aDocumentChecks)
921 rpDocumentCheck->check(
m_pDoc);
924 std::vector<std::unique_ptr<NodeCheck>> aNodeChecks;
926 aNodeChecks.push_back(std::make_unique<TableNodeMergeSplitCheck>(
m_aIssueCollection));
945 for (std::unique_ptr<NodeCheck>& rpNodeCheck : aNodeChecks)
947 rpNodeCheck->check(pNode);
954 for (sal_uInt16 nPage = 0; nPage < pModel->GetPageCount(); ++nPage)
956 SdrPage* pPage = pModel->GetPage(nPage);
957 for (
size_t nObject = 0; nObject < pPage->
GetObjCount(); ++nObject)
bool IsTableComplex() const
constexpr TypedWhichId< SvxCrossedOutItem > RES_CHRATR_CROSSEDOUT(5)
int GetAssignedOutlineStyleLevel() const
Represents the style of a paragraph.
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_CTL_FONT(27)
const OUString & GetText() const
SwDocShell * GetDocShell()
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
static css::uno::Reference< css::text::XTextContent > CreateXParagraph(SwDoc &rDoc, SwTextNode *pTextNode, css::uno::Reference< css::text::XText > const &xParentText=nullptr, const sal_Int32 nSelStart=-1, const sal_Int32 nSelEnd=-1)
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_FONTSIZE(8)
const SwPageDesc * FindPageDesc(size_t *pPgDescNdIdx=nullptr) const
Search PageDesc with which this node is formatted.
const SvxLanguageItem & GetLanguage(bool=true) const
virtual bool HasText() const
SdrObject * GetObj(size_t nNum) const
size_t GetObjCount() const
const std::vector< std::pair< OUString, OUString > > m_aNumberingCombinations
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
SwTableLine is one table row in the document model.
Dialog to specify the properties of date form field.
void checkObject(SdrObject *pObject)
css::uno::Reference< css::frame::XModel > GetModel() const
sal_Int32 GetAnyEnd() const
end (if available), else start
virtual SdrObjKind GetObjIdentifier() const
EmbeddedObjectRef * pObject
constexpr TypedWhichId< SvxPostureItem > RES_CHRATR_CJK_POSTURE(25)
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_FONT(7)
SwTableFormat * GetFrameFormat()
int GetAttrOutlineLevel() const
Returns outline level of this text node.
SwTextNode * m_pPreviousTextNode
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
SwTableNode * GetTableNode()
SwNodeType GetNodeType() const
A wrapper around SfxPoolItem to store the start position of (usually) a text portion, with an optional end.
const SfxPoolItem & GetDefault(sal_uInt16 nFormatHint) const
Get the default attribute in this document.
sal_Int32 GetStart() const
const SwTable & GetTable() const
constexpr TypedWhichId< SvxCharReliefItem > RES_CHRATR_RELIEF(36)
constexpr TypedWhichId< SwFormatAutoFormat > RES_TXTATR_AUTOFMT(50)
const Color & GetColorValue() const
sfx::AccessibilityIssueCollection & m_rIssueCollection
constexpr TypedWhichId< SvxWeightItem > RES_CHRATR_WEIGHT(15)
exports com.sun.star. text
SwTextAttr * Get(size_t nPos) const
constexpr TypedWhichId< SdrCustomShapeGeometryItem > SDRATTR_CUSTOMSHAPE_GEOMETRY(SDRATTR_CUSTOMSHAPE_FIRST+2)
std::vector< std::shared_ptr< AccessibilityIssue > > & getIssues()
SwNoTextNode * GetNoTextNode()
constexpr TypedWhichId< SvxShadowedItem > RES_CHRATR_SHADOWED(13)
virtual const SwDrawModel * GetDrawModel() const =0
Draw Model and id accessors.
OUString GetTitle() const
SwpHints & GetSwpHints()
getters for SwpHints
OUString SwResId(const char *pId)
constexpr TypedWhichId< SvxOverlineItem > RES_CHRATR_OVERLINE(38)
constexpr TypedWhichId< SvxEmphasisMarkItem > RES_CHRATR_EMPHASIS_MARK(33)
SwTableLines & GetTabLines()
SwTable is one table in the document model, containing rows (which contain cells).
constexpr TypedWhichId< SvxColorItem > RES_CHRATR_COLOR(3)
constexpr TypedWhichId< XFillColorItem > XATTR_FILLCOLOR(XATTR_FILL_FIRST+1)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > check(dp_misc::DescriptionInfoset const &infoset)
SwFrameFormat & GetMaster()
SwTextNode is a paragraph in the document model.
LanguageType GetLanguage() const
An SwTextAttr container, stores all directly formatted text portions for a text node.
constexpr TypedWhichId< SvxWeightItem > RES_CHRATR_CJK_WEIGHT(26)
const SwTextFormatColls * GetTextFormatColls() const
constexpr TypedWhichId< SvxWeightItem > RES_CHRATR_CTL_WEIGHT(31)
OUString GetTitle() const
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_CJK_FONT(22)
constexpr TypedWhichId< SvxPostureItem > RES_CHRATR_CTL_POSTURE(30)
SwTableBox is one table cell in the document model.
SwTableNode is derived from SwStartNode.
css::uno::Any * GetPropertyValueByName(const OUString &rPropName)
basegfx::BColor getBColor() const
SwTableNode * FindTableNode()
Search table node, in which it is.
const SwStartNode * FindFlyStartNode() const
SwFootnoteIdxs & GetFootnoteIdxs()
#define SAL_WARN(area, stream)
const SwFormatAutoFormat & GetAutoFormat() const
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_CTL_FONTSIZE(28)
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_CJK_FONTSIZE(23)
SwFrameFormat * GetFlyFormat() const
If node is in a fly return the respective format.
void remove_duplicates(std::vector< T > &rVector)
constexpr TypedWhichId< SvxPostureItem > RES_CHRATR_POSTURE(11)
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
AccessibilityIssueCollection m_aIssueCollection
Base class of the Writer document model elements.
SwTextFormatColl * GetTextColl() const
constexpr TypedWhichId< SvxContourItem > RES_CHRATR_CONTOUR(4)