Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f998f2c
VirtualBuffers: try re-using existing subtrees in renders.
michaelDCurran Aug 23, 2018
5df59c8
MSHTML vbufBackend: don't do partial re-renders as strange things hap…
michaelDCurran Aug 27, 2018
34b41da
VBufStorage and VBufBackend: remove unneeded code changes and clarify…
michaelDCurran Aug 30, 2018
e8a8233
VBufStorage: allow nodes to control when they can be reused in a re-r…
michaelDCurran Sep 3, 2018
60d1b75
VBufStorage and backends: If a part of a table needs re-rendering, ma…
michaelDCurran Sep 6, 2018
b32201b
VBufStorage and backends: ensure that a node and its descendants are …
michaelDCurran Sep 7, 2018
9a516e7
VBufStorage and backends: remove some log calls, beeps, and also swit…
michaelDCurran Sep 7, 2018
9a0ad64
Gecko virtualBuffer: ensure that getNVDAObjectFromIdentifier still wo…
michaelDCurran Sep 7, 2018
4061173
Merge branch 'master' into vbufPartialRender
michaelDCurran Sep 10, 2018
e42f93b
VBufStorage and backends: Ensure that reuse is denied when previous s…
michaelDCurran Sep 10, 2018
3b62ddd
Mozilla NVDAObject's setFocus method: ensure this blocks until a foc…
michaelDCurran Sep 19, 2018
dfed82a
Address review comments:
michaelDCurran Sep 20, 2018
6a982ed
Mozilla NVDAObject's _getPhysicalFocus method: handle case where acc…
michaelDCurran Sep 20, 2018
08b8857
Merge branch 'master' into vbufPartialRender
michaelDCurran Sep 20, 2018
0b6fad7
Fix comments.
michaelDCurran Sep 24, 2018
4f9b628
Merge branch 'master' into vbufPartialRender
michaelDCurran Sep 25, 2018
5d382e4
Update what's new
michaelDCurran Sep 25, 2018
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
Prev Previous commit
Next Next commit
VBufStorage and backends: ensure that a node and its descendants are …
…all re-rendered if a node has been given alternative text because the node had no useful descendants (E.g. an empty link).
  • Loading branch information
michaelDCurran committed Sep 7, 2018
commit b32201b5ab9168c0a434f124eebe13c1d3a6de30
6 changes: 6 additions & 0 deletions nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,20 +922,26 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc,
// If a link has no name, derive it from the URL.
buffer->addTextFieldNode(parentNode, NULL, getNameForURL(value));
}
// If any descendant is invalidated, this may change whether this node has no useful content.
parentNode->ensureDescendantsRequireParentUpdate();
}

if ((role == ROLE_SYSTEM_CELL || role == ROLE_SYSTEM_ROWHEADER || role == ROLE_SYSTEM_COLUMNHEADER||role==IA2_ROLE_UNKNOWN) && parentNode->getLength() == 0) {
// Always render a space for empty table cells and unknowns.
previousNode=buffer->addTextFieldNode(parentNode,previousNode,L" ");
if(previousNode&&!locale.empty()) previousNode->addAttribute(L"language",locale);
parentNode->isBlock=false;
// If any descendant is invalidated, this may change whether this node has no content.
parentNode->ensureDescendantsRequireParentUpdate();
}

if ((isInteractive || role == ROLE_SYSTEM_SEPARATOR) && parentNode->getLength() == 0) {
// If the node is interactive or otherwise relevant even when empty
// and it still has no content, render a space so the user can access the node.
previousNode=buffer->addTextFieldNode(parentNode,previousNode,L" ");
if(previousNode&&!locale.empty()) previousNode->addAttribute(L"language",locale);
// If any descendant is invalidated, this may change whether this node has no useful content.
parentNode->ensureDescendantsRequireParentUpdate();
}
}

Expand Down
6 changes: 6 additions & 0 deletions nvdaHelper/vbufBackends/mshtml/mshtml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,8 @@ if(!(formatState&FORMATSTATE_INSERTED)&&nodeName.compare(L"INS")==0) {
previousNode=buffer->addTextFieldNode(parentNode,NULL,contentString);
fillTextFormattingForNode(pHTMLDOMNode,previousNode);
}
// If any descendant is invalidated, this may change whether this node has no useful content.
parentNode->ensureDescendantsRequireParentUpdate();
}
}

Expand Down Expand Up @@ -1278,12 +1280,16 @@ if(!(formatState&FORMATSTATE_INSERTED)&&nodeName.compare(L"INS")==0) {
if(parentNode->getLength()==0) {
isBlock=false;
buffer->addTextFieldNode(parentNode,previousNode,L" ");
// If any descendant is invalidated, this may change whether this node has no useful content.
parentNode->ensureDescendantsRequireParentUpdate();
}
}

//If a node is interactive, and still has no content, add a space
if(isInteractive&&parentNode->getLength()==0) {
buffer->addTextFieldNode(parentNode,previousNode,L" ");
// If any descendant is invalidated, this may change whether this node has no useful content.
parentNode->ensureDescendantsRequireParentUpdate();
}
}

Expand Down
7 changes: 4 additions & 3 deletions nvdaHelper/vbufBase/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,10 @@ void VBufBackend_t::initialize() {
}

void VBufBackend_t::forceUpdate() {
//this->cancelPendingUpdate();
//this->update();
this->cancelPendingUpdate();
this->update();
}


LRESULT CALLBACK VBufBackend_t::destroy_callWndProcHook(int code, WPARAM wParam,LPARAM lParam) {
CWPSTRUCT* pcwp=(CWPSTRUCT*)lParam;
if((pcwp->message==WM_DESTROY)) {
Expand Down Expand Up @@ -181,12 +180,14 @@ bool VBufBackend_t::invalidateSubtree(VBufStorage_controlFieldNode_t* node) {
});
// Now mark this node as invalid.
pendingInvalidSubtreesList.push_back(node);
LOG_INFO(L"Invalidated node "<<node->getDebugInfo());
this->requestUpdate();
return true;
}

void VBufBackend_t::update() {
if(inUpdate) {
Beep(550,40);
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this to prevent updates requested by win events during a render from running within COM calls? It might be worth commenting the reason for possible re-entry. Also, if this does occur, how does the pending update get re-requested? I guess some other event will fire eventually, but that seems unreliable. Or am I missing something?

}
inUpdate=true;
Expand Down
5 changes: 4 additions & 1 deletion nvdaHelper/vbufBase/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ static LRESULT CALLBACK destroy_callWndProcHook(int code, WPARAM wParam, LPARAM
*/
virtual void render(VBufStorage_buffer_t* buffer, int docHandle, int ID, VBufStorage_controlFieldNode_t* oldNode=NULL)=0;

bool inUpdate {false};
/**
* Tracks if the backend is currently being updated, and if so does not allow update to become reentrant.
*/
bool inUpdate {false};

/**
* Updates the content of the buffer.
Expand Down
14 changes: 13 additions & 1 deletion nvdaHelper/vbufBase/storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,18 @@ VBufStorage_controlFieldNode_t::VBufStorage_controlFieldNode_t(int docHandle, in
LOG_DEBUG(L"controlFieldNode initialization at "<<this<<L", with docHandle of "<<identifier.docHandle<<L" and ID of "<<identifier.ID);
}

void VBufStorage_controlFieldNode_t::ensureDescendantsRequireParentUpdate() {
this->alwaysRerenderChildren=true;
for(auto child=this->getFirstChild();child!=nullptr;child=child->getNext()) {
auto childControlField=dynamic_cast<VBufStorage_controlFieldNode_t*>(child);
if(childControlField) {
childControlField->requiresParentUpdate=true;
LOG_INFO(L"making child controlField require parent update. childControlField "<<childControlField->getDebugInfo());
childControlField->ensureDescendantsRequireParentUpdate();
}
}
}

bool VBufStorage_controlFieldNode_t::getIdentifier(int* docHandle, int* ID) {
*docHandle=this->identifier.docHandle;
*ID=this->identifier.ID;
Expand All @@ -355,7 +367,7 @@ bool VBufStorage_controlFieldNode_t::getIdentifier(int* docHandle, int* ID) {

std::wstring VBufStorage_controlFieldNode_t::getDebugInfo() const {
std::wostringstream s;
s<<L"control "<<this->VBufStorage_fieldNode_t::getDebugInfo()<<L", docHandle "<<identifier.docHandle<<L", ID is "<<identifier.ID;
s<<L"control "<<this->VBufStorage_fieldNode_t::getDebugInfo()<<L", docHandle "<<identifier.docHandle<<L", ID is "<<identifier.ID<<L", requiresParentUpdate "<<requiresParentUpdate<<L", allowReuseInAncestorUpdate "<<allowReuseInAncestorUpdate<<L", denyReuseIfPreviousSiblingsChanged "<<denyReuseIfPreviousSiblingsChanged<<L", alwaysRerenderChildren "<<alwaysRerenderChildren;
return s.str();
}

Expand Down
8 changes: 8 additions & 0 deletions nvdaHelper/vbufBase/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,14 @@ class VBufStorage_controlFieldNode_t : public VBufStorage_fieldNode_t {
*/
bool alwaysRerenderChildren {false};

/**
* Sets the requiresParentUpdate property to true on all descendants of this node, and sets alwaysRerenderChildren to true on this node and all descendants.
* This method is useful if some alternative text has been added to a node because its descendants don't seem to contain useful content (E.g. an empty link).
* This ensures that if a descendant is re-rendered, this node should also be re-rendered (as the alternative text may no longer be needed).
* It also ensures that if this node is re-rendered, none of its children are reused from here or somewhere else in the tree as the reused node may not have been makred as requiring a prent update.
*/
void ensureDescendantsRequireParentUpdate();

/**
* retreaves the node's doc handle and ID.
* @param docHandle a memory location in which the doc handle will be placed.
Expand Down