Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Comment thread
feerrenrut marked this conversation as resolved.
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();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the calls to child.clear are not necessary I think, as CComVariant's destructor does this itself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right, explicitly calling clear isn't necessary. I left them in to maintain the existing timing of the release. As much as possible I was trying to avoid the output binary from changing. I can look at this again if you would like?

}
free(varChildren);

} else if (renderSelectedItemOnly) {
CComPtr<IAccessible2> item = this->getSelectedItem(pacc, IA2AttribsMap);
if (item) {
Expand Down
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