Skip to content

Commit

Permalink
Add helper: getAccessibleChildren (PR #13126)
Browse files Browse the repository at this point in the history
Make all usages of AccessibleChildren conform to a consistent approach.
Management of resources is automatic.
Related to #13106
  • Loading branch information
feerrenrut committed Jan 17, 2022
1 parent 2d352dd commit c6a6df8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 64 deletions.
31 changes: 31 additions & 0 deletions nvdaHelper/common/ia2utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,37 @@ void IA2AttribsToMap(const wstring &attribsString, map<wstring, wstring> &attrib
}
}

std::pair<std::vector<CComVariant>, HRESULT>
getAccessibleChildren(IAccessible* pacc, long indexOfFirstChild, long maxChildCount) {
try {
std::vector<CComVariant> varChildren(maxChildCount);
const auto res = AccessibleChildren(
pacc,
indexOfFirstChild,
maxChildCount,
varChildren.data(),
&maxChildCount
);
if (res != S_OK) {
return std::make_pair(
std::vector<CComVariant>(0),
res
);
}
// shrink the vector in case less children were returned.
// so that varChildren.size() will equal actual filled size
varChildren.resize(maxChildCount);
// no need to shrink to fit, make_pair will copy the vector, using only the first varChildren.size() elements.
return std::make_pair(varChildren, S_OK);
}
catch (std::bad_array_new_length&) {
return std::make_pair(
std::vector<CComVariant>(0),
S_FALSE
);
}
}

CComPtr<IAccessibleHyperlink> HyperlinkGetter::next() {
return this->get(this->index++);
}
Expand Down
8 changes: 8 additions & 0 deletions nvdaHelper/common/ia2utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ This license can be found at:
#include <atlcomcli.h>
#include <string>
#include <map>
#include <vector>
#include <utility>
#include <memory>
#include <ia2.h>

Expand All @@ -34,6 +36,12 @@ bool fetchIA2Attributes(IAccessible2* pacc2, std::map<std::wstring, std::wstring
*/
void IA2AttribsToMap(const std::wstring &attribsString, std::map<std::wstring, std::wstring> &attribsMap);

/**
* Helper to collect the children for an IAccessible, uses memory managed types that will clear / delete automatically.
*/
std::pair<std::vector<CComVariant>, HRESULT>
getAccessibleChildren(IAccessible* pacc, long indexOfFirstChild, long maxChildCount);

/**
* Base class to support retrieving hyperlinks (embedded objects) from
* IAccessibleHypertext or IAccessibleHypertext2.
Expand Down
37 changes: 12 additions & 25 deletions nvdaHelper/vbufBackends/adobeAcrobat/adobeAcrobat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This license can be found at:
#include <iomanip>
#include <windows.h>
#include <oleacc.h>
#include <common/ia2utils.h>
#include <remote/nvdaHelperRemote.h>
#include <vbufBase/backend.h>
#include <common/log.h>
Expand Down Expand Up @@ -619,30 +620,22 @@ AdobeAcrobatVBufStorage_controlFieldNode_t* AdobeAcrobatVBufBackend_t::fillVBuf(

} else if (childCount > 0) {
// Iterate through the children.
LOG_DEBUG(L"Allocate memory to hold children");
VARIANT* varChildren;
if((varChildren=(VARIANT*)malloc(sizeof(VARIANT)*childCount))==NULL) {
LOG_DEBUG(L"Error allocating varChildren memory");
if (stdName)
SysFreeString(stdName);
return NULL;
}
LOG_DEBUG(L"Fetch children with AccessibleChildren");
if((res=AccessibleChildren(pacc,0,childCount,varChildren,(long*)(&childCount)))!=S_OK) {
LOG_DEBUG(L"AccessibleChildren returned "<<res);
auto[varChildren, accChildRes] = getAccessibleChildren(pacc, 0, childCount);
if(S_OK != accChildRes || varChildren.size() == 0) {
LOG_DEBUG(L"Failed to get AccessibleChildren (count: " << childCount << L"), res: " << accChildRes);
childCount=0;
}
LOG_DEBUG(L"got "<<childCount<<L" children");
for(int i=0;i<childCount;++i) {
LOG_DEBUG(L"child "<<i);
if(varChildren[i].vt==VT_DISPATCH) {
LOG_DEBUG(L"got "<< varChildren.size() << L" children");
for(auto i = 0u; i < varChildren.size(); ++i) {
LOG_DEBUG(L"child " << i);
if(VT_DISPATCH == varChildren[i].vt) {
LOG_DEBUG(L"QueryInterface dispatch child to IID_IAccesible");
IAccessible* childPacc=NULL;
if((res=varChildren[i].pdispVal->QueryInterface(IID_IAccessible,(void**)(&childPacc)))!=S_OK) {
LOG_DEBUG(L"varChildren["<<i<<L"].pdispVal->QueryInterface to IID_iAccessible returned "<<res);
childPacc=NULL;
CComQIPtr<IAccessible, &IID_IAccessible> childPacc(varChildren[i].pdispVal);
if(!childPacc) {
LOG_DEBUG(L"varChildren[" << i << L"]: QueryInterface to IID_iAccessible failed.");
}
if(childPacc) {
else {
if (this->isXFA) {
// HACK: If this is an XFA document, we must call WindowFromAccessibleObject() so that AccessibleObjectFromEvent() will work for this node.
HWND tempHwnd;
Expand All @@ -654,15 +647,9 @@ AdobeAcrobatVBufStorage_controlFieldNode_t* AdobeAcrobatVBufBackend_t::fillVBuf(
} else {
LOG_DEBUG(L"Error in calling fillVBuf");
}
LOG_DEBUG(L"releasing child IAccessible object");
childPacc->Release();
}
}
VariantClear(&(varChildren[i]));
}
LOG_DEBUG(L"Freeing memory holding children");
free(varChildren);

} else {
// No children, so this is a leaf node.
if (!this->isXFA && !stdName) {
Expand Down
30 changes: 11 additions & 19 deletions nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -950,25 +950,20 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(

} else if (renderChildren && childCount > 0) {
// The object has no text, but we do want to render its children.
VARIANT* varChildren;
if(!(varChildren=(VARIANT*)malloc(sizeof(VARIANT)*childCount))) {
LOG_DEBUG(L"Error allocating varChildren memory");
return NULL;
auto [varChildren, accChildRes] = getAccessibleChildren(pacc, 0, childCount);
if (S_OK != accChildRes || varChildren.size() == 0) {
LOG_ERROR(L"AccessibleChildren failed (count: " << childCount << L"), res: " << accChildRes);
}
long accessibleChildrenCount = 0;
if(AccessibleChildren(pacc,0,childCount,varChildren,&accessibleChildrenCount)!=S_OK) {
LOG_DEBUG(L"AccessibleChildren failed");
accessibleChildrenCount=0;
}
for(long i=0;i<accessibleChildrenCount;++i) {
if (varChildren[i].vt != VT_DISPATCH) {
VariantClear(&(varChildren[i]));
LOG_DEBUG(L"got " << varChildren.size() << L" children");

for(CComVariant& child : varChildren) {
if (child.vt != VT_DISPATCH || !child.pdispVal) {
child.Clear();
continue;
}
IAccessible2* childPacc=NULL;
if(varChildren[i].pdispVal) varChildren[i].pdispVal->QueryInterface(IID_IAccessible2,(void**)&childPacc);
CComQIPtr< IAccessible2, &IID_IAccessible2> childPacc(child.pdispVal);
if (!childPacc) {
VariantClear(&(varChildren[i]));
child.Clear();
continue;
}
tempNode = this->fillVBuf(
Expand All @@ -986,11 +981,8 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
}
else
LOG_DEBUG(L"Error in calling fillVBuf");
childPacc->Release();
VariantClear(&(varChildren[i]));
child.Clear();
}
free(varChildren);

} else if (renderSelectedItemOnly) {
CComPtr<IAccessible2> item = this->getSelectedItem(pacc, IA2AttribsMap);
if (item) {
Expand Down
19 changes: 13 additions & 6 deletions nvdaHelper/vbufBackends/lotusNotesRichText/lotusNotesRichText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This license can be found at:
#include <windows.h>
#include <oleacc.h>
#include <common/log.h>
#include <common/ia2utils.h>
#include <remote/nvdaHelperRemote.h>
#include <vbufBase/backend.h>
#include "lotusNotesRichText.h"
Expand Down Expand Up @@ -170,12 +171,18 @@ void lotusNotesRichTextVBufBackend_t::render(VBufStorage_buffer_t* buffer, int d
VBufStorage_fieldNode_t* previousNode=NULL;
long childCount=0;
pacc->get_accChildCount(&childCount);
VARIANT* varChildren=(VARIANT*)malloc(sizeof(VARIANT)*childCount);
HRESULT hRes;
hRes=AccessibleChildren(pacc,0,childCount,varChildren,&childCount);
for(int i=0;i<childCount;++i) {
if(varChildren[i].vt==VT_I4) {
previousNode=this->renderControlContent(buffer,parentNode,previousNode,docHandle,pacc,varChildren[i].lVal);

auto [varChildren, hres] = getAccessibleChildren(pacc, 0, childCount);
for(CComVariant& child : varChildren) {
if(VT_I4 == child.vt) {
previousNode = this->renderControlContent(
buffer,
parentNode,
previousNode,
docHandle,
pacc,
child.lVal
);
}
}
} else {
Expand Down
28 changes: 14 additions & 14 deletions nvdaHelper/vbufBackends/webKit/webKit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This license can be found at:
#include <ia2.h>
#include <remote/nvdaHelperRemote.h>
#include <common/log.h>
#include <common/ia2utils.h>
#include <vbufBase/backend.h>
#include "webKit.h"

Expand Down Expand Up @@ -123,20 +124,19 @@ VBufStorage_fieldNode_t* WebKitVBufBackend_t::fillVBuf(int docHandle, IAccessibl

// Iterate through the children.
if (childCount > 0) {
auto varChildren = make_unique<CComVariant[]>(childCount);
if(AccessibleChildren(pacc,0,childCount,varChildren.get(),(long*)(&childCount))!=S_OK) {
childCount=0;
}
for(int i=0;i<childCount;i++) {
if(varChildren[i].vt!=VT_DISPATCH) {
continue;
}
CComQIPtr<IAccessible2> childPacc = varChildren[i].pdispVal;
if(!childPacc) {
continue;
}
if((tempNode=this->fillVBuf(docHandle,childPacc,buffer,parentNode,previousNode))!=NULL) {
previousNode=tempNode;
auto [varChildren, accChildrenRes] = getAccessibleChildren(pacc, 0, childCount);
if (S_OK == accChildrenRes) {
for (CComVariant& child : varChildren) {
if (VT_DISPATCH != child.vt) {
continue;
}
CComQIPtr<IAccessible2> childPacc(child.pdispVal);
if (!childPacc) {
continue;
}
if ((tempNode = this->fillVBuf(docHandle, childPacc, buffer, parentNode, previousNode)) != NULL) {
previousNode = tempNode;
}
}
}
} else {
Expand Down

0 comments on commit c6a6df8

Please sign in to comment.