Skip to content

Commit 99636e1

Browse files
authored
Merge 71673d8 into 2e3041f
2 parents 2e3041f + 71673d8 commit 99636e1

21 files changed

Lines changed: 526 additions & 79 deletions

File tree

nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp

Lines changed: 75 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2007-2017 NV Access Limited, Mozilla Corporation
4+
Copyright 2007-2022 NV Access Limited, Mozilla Corporation
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -361,9 +361,64 @@ CComPtr<IAccessible2> getTextBoxInComboBox(
361361
return child;
362362
}
363363

364+
365+
std::tuple<long, CComBSTR> getRoleLongRoleString(CComPtr<IAccessible2> pacc, CComVariant varChild) {
366+
long role = 0;
367+
CComBSTR roleString;
368+
CComVariant varRole;
369+
if (pacc->role(&role) != S_OK) {
370+
role = IA2_ROLE_UNKNOWN;
371+
}
372+
if (role == 0) {
373+
if (pacc->get_accRole(varChild, &varRole) != S_OK) {
374+
LOG_DEBUG(L"accRole failed");
375+
}
376+
if (varRole.vt == VT_I4) {
377+
role = varRole.lVal;
378+
}
379+
else if (varRole.vt == VT_BSTR) {
380+
roleString = varRole.bstrVal;
381+
}
382+
}
383+
return std::make_tuple(role, roleString);
384+
}
385+
386+
364387
const vector<wstring>ATTRLIST_ROLES(1, L"IAccessible2::attribute_xml-roles");
365388
const wregex REGEX_PRESENTATION_ROLE(L"IAccessible2\\\\:\\\\:attribute_xml-roles:.*\\bpresentation\\b.*;");
366389

390+
391+
void GeckoVBufBackend_t::fillVBufAriaDetails(
392+
int docHandle,
393+
CComPtr<IAccessible2> pacc,
394+
VBufStorage_buffer_t& buffer,
395+
VBufStorage_controlFieldNode_t& parentNode,
396+
const std::wstring& roleAttr
397+
){
398+
/* Set the details role by checking for both IA2_RELATION_DETAILS and IA2_RELATION_DETAILS_FOR as one
399+
of the nodes in the relationship will not be in the buffer yet */
400+
std::optional<int> detailsId = getRelationId(IA2_RELATION_DETAILS, pacc);
401+
std::optional<int> detailsForId = getRelationId(IA2_RELATION_DETAILS_FOR, pacc);
402+
VBufStorage_controlFieldNode_t* detailsParentNode = nullptr;
403+
std::optional<std::wstring> detailsRole;
404+
if (detailsId.has_value()) {
405+
parentNode.addAttribute(L"hasDetails", L"true");
406+
detailsParentNode = &parentNode;
407+
auto detailsChildNode = buffer.getControlFieldNodeWithIdentifier(docHandle, detailsId.value());
408+
if (detailsChildNode != nullptr) {
409+
detailsRole = detailsChildNode->getAttribute(L"role");
410+
}
411+
}
412+
if (detailsForId.has_value()) {
413+
detailsParentNode = buffer.getControlFieldNodeWithIdentifier(docHandle, detailsForId.value());
414+
detailsRole = roleAttr;
415+
}
416+
if (detailsParentNode != nullptr && detailsRole.has_value()) {
417+
detailsParentNode->addAttribute(L"detailsRole", detailsRole.value());
418+
}
419+
}
420+
421+
367422
VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
368423
IAccessible2* pacc,
369424
VBufStorage_buffer_t* buffer,
@@ -383,6 +438,7 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
383438
varChild.vt=VT_I4;
384439
varChild.lVal=0;
385440
wostringstream s;
441+
std::wstring roleAttr;
386442

387443
//get docHandle -- IAccessible2 windowHandle
388444
HWND docHwnd;
@@ -436,21 +492,10 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
436492
}
437493

438494
//Get role -- IAccessible2 role
439-
long role=0;
440-
BSTR roleString=NULL;
441-
if(pacc->role(&role)!=S_OK)
442-
role=IA2_ROLE_UNKNOWN;
443-
VARIANT varRole;
444-
VariantInit(&varRole);
445-
if(role==0) {
446-
if(pacc->get_accRole(varChild,&varRole)!=S_OK) {
447-
LOG_DEBUG(L"accRole failed");
448-
}
449-
if(varRole.vt==VT_I4)
450-
role=varRole.lVal;
451-
else if(varRole.vt==VT_BSTR)
452-
roleString=varRole.bstrVal;
453-
}
495+
long role = 0;
496+
CComBSTR roleString;
497+
CComPtr<IAccessible2> smartPacc = CComQIPtr<IAccessible2>(pacc);
498+
std::tie(role, roleString) = getRoleLongRoleString(smartPacc, CComVariant(&varChild));
454499

455500
// Specifically force the role of ARIA treegrids from outline to table.
456501
// We do this very early on in the rendering so that all our table logic applies.
@@ -460,14 +505,13 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
460505
}
461506
}
462507

463-
//Add role as an attrib
464-
if(roleString)
465-
s<<roleString;
466-
else
467-
s<<role;
468-
parentNode->addAttribute(L"IAccessible::role",s.str());
469-
s.str(L"");
470-
VariantClear(&varRole);
508+
if (roleString) {
509+
roleAttr = roleString;
510+
} else {
511+
roleAttr = std::to_wstring(role);
512+
}
513+
514+
parentNode->addAttribute(L"IAccessible::role", roleAttr);
471515

472516
//get states -- IAccessible accState
473517
VARIANT varState;
@@ -1153,13 +1197,13 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
11531197
parentNode->addAttribute(L"descriptionIsContent", L"true");
11541198
}
11551199

1156-
1157-
/* Set the details summary by checking for both IA2_RELATION_DETAILS and IA2_RELATION_DETAILS_FOR as one
1158-
of the nodes in the relationship will not be in the buffer yet */
1159-
std::optional<int> detailsId = getRelationId(IA2_RELATION_DETAILS, pacc);
1160-
if (detailsId) {
1161-
parentNode->addAttribute(L"hasDetails", L"true");
1162-
}
1200+
fillVBufAriaDetails(
1201+
docHandle,
1202+
smartPacc,
1203+
*buffer,
1204+
*parentNode,
1205+
roleAttr
1206+
);
11631207

11641208
// Clean up.
11651209
if(name)

nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2010 NVDA contributers.
4+
Copyright 2006-2022 NVDA contributors.
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -33,6 +33,14 @@ class GeckoVBufBackend_t: public VBufBackend_t {
3333
bool ignoreInteractiveUnlabelledGraphics=false
3434
);
3535

36+
void fillVBufAriaDetails(
37+
int docHandle,
38+
CComPtr<IAccessible2> pacc,
39+
VBufStorage_buffer_t& buffer,
40+
VBufStorage_controlFieldNode_t& parentNode,
41+
const std::wstring& roleAttr
42+
);
43+
3644
void versionSpecificInit(IAccessible2* pacc);
3745

3846
void fillTableCellInfo_IATable2(VBufStorage_controlFieldNode_t* node, IAccessibleTableCell* paccTableCell);

nvdaHelper/vbufBase/storage.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2010 NVDA contributers.
4+
Copyright 2006-2022 NVDA contributors.
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -23,6 +23,7 @@ This license can be found at:
2323
#include <vector>
2424
#include <sstream>
2525
#include <algorithm>
26+
#include <optional>
2627
#include <common/xml.h>
2728
#include <common/log.h>
2829
#include "utils.h"
@@ -321,6 +322,16 @@ bool VBufStorage_fieldNode_t::addAttribute(const std::wstring& name, const std::
321322
return true;
322323
}
323324

325+
std::optional<std::wstring> VBufStorage_fieldNode_t::getAttribute(const std::wstring& name) {
326+
LOG_DEBUG(L"Getting attribute " << name);
327+
auto foundAttrib = attributes.find(name);
328+
if (foundAttrib != attributes.end()) {
329+
return foundAttrib->second;
330+
}
331+
LOG_ERROR(L"Couldn't find attribute " << name);
332+
return std::nullopt;
333+
}
334+
324335
std::wstring VBufStorage_fieldNode_t::getAttributesString() const {
325336
std::wstring attributesString;
326337
for(std::map<std::wstring,std::wstring>::const_iterator i=attributes.begin();i!=attributes.end();++i) {
@@ -899,7 +910,7 @@ VBufStorage_controlFieldNode_t* VBufStorage_buffer_t::getControlFieldNodeWithIde
899910
std::map<VBufStorage_controlFieldNodeIdentifier_t,VBufStorage_controlFieldNode_t*>::iterator i=this->controlFieldNodesByIdentifier.find(identifier);
900911
if(i==this->controlFieldNodesByIdentifier.end()) {
901912
LOG_DEBUG(L"No controlFieldNode with identifier, returning NULL");
902-
return NULL;
913+
return nullptr;
903914
}
904915
VBufStorage_controlFieldNode_t* node=i->second;
905916
nhAssert(node); //Node can not be NULL

nvdaHelper/vbufBase/storage.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2010 NVDA contributers.
4+
Copyright 2006-2022 NVDA contributors.
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -21,6 +21,7 @@ This license can be found at:
2121
#include <list>
2222
#include <vector>
2323
#include <regex>
24+
#include <optional>
2425

2526
/**
2627
* values to indicate a direction for searching
@@ -266,6 +267,13 @@ class VBufStorage_fieldNode_t {
266267
*/
267268
bool addAttribute(const std::wstring& name, const std::wstring& value);
268269

270+
/**
271+
* Gets an attribute value for this field.
272+
* @param name the name of the attribute
273+
* @return the attribute if the attribute exists, NULL if it doesn't exist.
274+
*/
275+
std::optional<std::wstring> getAttribute(const std::wstring& name);
276+
269277
/**
270278
* @return a string of all the attributes in this field, format of name:value pares separated by a semi colon.
271279
*/

readme.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Additionally, the following build time dependencies are included in the miscDeps
111111
* xgettext and msgfmt from [GNU gettext](https://sourceforge.net/projects/cppcms/files/boost_locale/gettext_for_windows/)
112112

113113
The following dependencies aren't needed by most people, and are not included in Git submodules:
114-
* To generate developer documentation for nvdaHelper: [Doxygen Windows installer](http://www.doxygen.nl/download.html), version 1.8.15:
114+
* To generate [developer documentation for nvdaHelper](#building-nvdahelper-developer-documentation): [Doxygen Windows installer](http://www.doxygen.nl/download.html), version 1.8.15:
115115
* When you are using Visual Studio Code as your integrated development environment of preference, you can make use of our [prepopulated workspace configuration](https://github.com/nvaccess/vscode-nvda/) for [Visual Studio Code](https://code.visualstudio.com/).
116116
While this VSCode project is not included as a submodule in the NVDA repository, you can easily check out the workspace configuration in your repository by executing the following from the root of the repository.
117117

@@ -212,13 +212,16 @@ scons devDocs
212212

213213
The documentation will be placed in the `NVDA` folder in the output directory.
214214

215+
#### Building nvdaHelper developer documentation
216+
215217
To generate developer documentation for nvdaHelper (not included in the devDocs target):
216218

217219
```
218220
scons devDocs_nvdaHelper
219221
```
220222

221223
The documentation will be placed in the `devDocs\nvdaHelper` folder in the output directory.
224+
This requires having Doxygen installed.
222225

223226
### Generate debug symbols archive
224227
To generate an archive of debug symbols for the various dll/exe binaries, type:

source/IAccessibleHandler/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2006-2021 NV Access Limited, Łukasz Golonka, Leonard de Ruijter
2+
# Copyright (C) 2006-2022 NV Access Limited, Łukasz Golonka, Leonard de Ruijter
33
# This file is covered by the GNU General Public License.
44
# See the file COPYING for more details.
55

@@ -184,6 +184,8 @@
184184
IA2.IA2_ROLE_BLOCK_QUOTE: controlTypes.Role.BLOCKQUOTE,
185185
IA2.IA2_ROLE_LANDMARK: controlTypes.Role.LANDMARK,
186186
IA2.IA2_ROLE_MARK: controlTypes.Role.MARKED_CONTENT,
187+
IA2.IA2_ROLE_COMMENT: controlTypes.Role.COMMENT,
188+
IA2.IA2_ROLE_SUGGESTION: controlTypes.Role.SUGGESTION,
187189
# some common string roles
188190
"frame": controlTypes.Role.FRAME,
189191
"iframe": controlTypes.Role.INTERNALFRAME,

source/NVDAObjects/IAccessible/chromium.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
1-
#NVDAObjects/IAccessible/chromium.py
2-
#A part of NonVisual Desktop Access (NVDA)
3-
#This file is covered by the GNU General Public License.
4-
#See the file COPYING for more details.
5-
# Copyright (C) 2010-2013 NV Access Limited
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# This file is covered by the GNU General Public License.
3+
# See the file COPYING for more details.
4+
# Copyright (C) 2010-2022 NV Access Limited
65

76
"""NVDAObjects for the Chromium browser project
87
"""
98

9+
from typing import Dict, Optional
1010
from comtypes import COMError
11-
import oleacc
1211
import controlTypes
1312
from NVDAObjects.IAccessible import IAccessible
1413
from virtualBuffers.gecko_ia2 import Gecko_ia2 as GeckoVBuf, Gecko_ia2_TextInfo as GeckoVBufTextInfo
1514
from . import ia2Web
1615
from logHandler import log
1716

1817

18+
supportedAriaDetailsRoles: Dict[str, Optional[controlTypes.Role]] = {
19+
"comment": controlTypes.Role.COMMENT,
20+
"doc-footnote": controlTypes.Role.FOOTNOTE,
21+
# These roles are current unsupported by IAccessible2,
22+
# and as such, have not been fully implemented in NVDA.
23+
# They can only be fetched via the IA2Attribute "details-roles",
24+
# which is only supported in Chrome.
25+
# Currently maps to the IA2 role ROLE_LIST_ITEM
26+
"doc-endnote": None, # controlTypes.Role.ENDNOTE
27+
# Currently maps to the IA2 role ROLE_PARAGRAPH
28+
"definition": None, # controlTypes.Role.DEFINITION
29+
}
30+
"""
31+
details-roles attribute is only defined in Chrome as of May 2022.
32+
Refer to ComputeDetailsRoles:
33+
https://chromium.googlesource.com/chromium/src/+/main/ui/accessibility/platform/ax_platform_node_base.cc#2419
34+
"""
35+
36+
1937
class ChromeVBufTextInfo(GeckoVBufTextInfo):
2038

2139
def _calculateDescriptionFrom(self, attrs) -> controlTypes.DescriptionFrom:

source/NVDAObjects/IAccessible/ia2Web.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# A part of NonVisual Desktop Access (NVDA)
22
# This file is covered by the GNU General Public License.
33
# See the file COPYING for more details.
4-
# Copyright (C) 2006-2021 NV Access Limited
4+
# Copyright (C) 2006-2022 NV Access Limited
55

66
"""Base classes with common support for browsers exposing IAccessible2.
77
"""
@@ -62,6 +62,25 @@ def _get_detailsSummary(self) -> typing.Optional[str]:
6262
def hasDetails(self) -> bool:
6363
return bool(self.IA2Attributes.get("details-roles"))
6464

65+
def _get_detailsRole(self) -> typing.Optional[controlTypes.Role]:
66+
from .chromium import supportedAriaDetailsRoles
67+
# Currently only defined in Chrome as of May 2022
68+
# Refer to ComputeDetailsRoles
69+
# https://chromium.googlesource.com/chromium/src/+/main/ui/accessibility/platform/ax_platform_node_base.cc#2419
70+
detailsRoles = self.IA2Attributes.get("details-roles")
71+
if not detailsRoles:
72+
if config.conf["debugLog"]["annotations"]:
73+
log.debug("details-roles not found")
74+
return None
75+
76+
firstDetailsRole = detailsRoles.split(" ")[0]
77+
# return a supported details role
78+
detailsRole = supportedAriaDetailsRoles.get(firstDetailsRole)
79+
if config.conf["debugLog"]["annotations"]:
80+
log.debug(f"detailsRole: {repr(detailsRole)}")
81+
return detailsRole
82+
83+
6584
def _get_isCurrent(self) -> controlTypes.IsCurrent:
6685
ia2attrCurrent: str = self.IA2Attributes.get("current", "false")
6786
try:

0 commit comments

Comments
 (0)