Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gecko VBufBackend: greatly speed up subtree re-renders when part of a document has changed #8678

Merged
merged 17 commits into from
Sep 25, 2018
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
62 changes: 26 additions & 36 deletions nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ template<typename TableType> inline void fillTableCounts(VBufStorage_controlFiel
}
}

inline int updateTableCounts(IAccessibleTableCell* tableCell, VBufStorage_buffer_t* tableBuffer) {
inline int getTableIDFromCell(IAccessibleTableCell* tableCell) {
IUnknown* unk = NULL;
if (tableCell->get_table(&unk) != S_OK || !unk)
return 0;
Expand All @@ -130,26 +130,8 @@ inline int updateTableCounts(IAccessibleTableCell* tableCell, VBufStorage_buffer
unk->Release();
if (res != S_OK || !acc)
return 0;
HWND docHwnd;
int id;
if (acc->get_windowHandle(&docHwnd) != S_OK
|| acc->get_uniqueID((long*)&id) != S_OK) {
acc->Release();
return 0;
}
const int docHandle = HandleToUlong(docHwnd);
VBufStorage_controlFieldNode_t* node = tableBuffer->getControlFieldNodeWithIdentifier(docHandle, id);
if (!node) {
acc->Release();
return 0;
}
IAccessibleTable2* table = NULL;
if (acc->QueryInterface(IID_IAccessibleTable2, (void**)&table) != S_OK || !table) {
acc->Release();
return 0;
}
fillTableCounts<IAccessibleTable2>(node, acc, table);
table->Release();
int id=0;
acc->get_uniqueID((long*)&id);
acc->Release();
return id;
}
Expand Down Expand Up @@ -394,15 +376,6 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc,
nhAssert(parentNode); //new node must have been created
previousNode=NULL;

if(paccTable2) {
LOG_DEBUG(L"Setting node's denyReuseIfPreviousSiblingsChanged to true");
parentNode->denyReuseIfPreviousSiblingsChanged=true;
LOG_DEBUG(L"Setting node's requiresParentUpdate to true");
parentNode->requiresParentUpdate=true;
LOG_DEBUG(L"Setting node's alwaysRerenderChildren to true");
parentNode->alwaysRerenderChildren=true;
}

//Get role -- IAccessible2 role
long role=0;
BSTR roleString=NULL;
Expand Down Expand Up @@ -681,11 +654,28 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc,
paccTableCell=nullptr;
}

if(paccTableCell) {
LOG_DEBUG(L"Setting node's requiresParentUpdate back to false as this is a table cell");
parentNode->requiresParentUpdate=false;
LOG_DEBUG(L"Setting node's alwaysRerenderChildren back to false as this is a table cell");
parentNode->alwaysRerenderChildren=false;
if(paccTable2) {
// We are rendering a node that is part of a table (row group, row or cell).
// Set some properties to ensure that this and other nodes in the table aare correctly re-rendered if the table changes,
// so that the table's row and column cordinates remain accurate.
// setting denyReuseIfPreviousSiblingsChange ensures that if any part of the table is added or removed previous to this node,
// his node will not be reused (as its row / column coordinates would now be out of date).
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: his -> this

LOG_DEBUG(L"Setting node's denyReuseIfPreviousSiblingsChanged to true");
parentNode->denyReuseIfPreviousSiblingsChanged=true;
if(!paccTableCell) { // just rows and row groups
// setting requiresParentUpdate ensures that if this node is specifically invalidated,
// its parent will also be invalidated.
// For example, if this is a table row, its rerendering may change the number of cells inside.
Copy link
Contributor

Choose a reason for hiding this comment

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

Re-rendering a table row wouldn't change subsequent table row coordinates. However, this does apply to row groups, so you can just change the comment here (and on the next line) to reflect that.

// this in tern would affect the coordinates of all table cells in table rows after this row.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: tern -> turn

// Thus, ensuring we rerender this node's parent, gives a chance to rerender other table rows.
LOG_DEBUG(L"Setting node's requiresParentUpdate to true");
parentNode->requiresParentUpdate=true;
// Setting alwaysRerenderChildren ensures that if this node is rerendered, none of its children are reused.
// For example, if this is a table row that is rerendered (perhaps due to a previous table row being added),
// this row's cells can't be reused because their coordinates would now be out of date.
LOG_DEBUG(L"Setting node's alwaysRerenderChildren to true");
parentNode->alwaysRerenderChildren=true;
}
}

// For IAccessibleTable, we must always be passed the table interface by the caller.
Expand All @@ -700,7 +690,7 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc,
this->fillTableCellInfo_IATable2(parentNode, paccTableCell);
if (!paccTable2) {
// This is an update; we're not rendering the entire table.
tableID = updateTableCounts(paccTableCell, this);
tableID = getTableIDFromCell(paccTableCell);
}
paccTableCell->Release();
paccTableCell = NULL;
Expand Down
14 changes: 9 additions & 5 deletions nvdaHelper/vbufBase/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,6 @@ bool VBufBackend_t::invalidateSubtree(VBufStorage_controlFieldNode_t* node) {
}

void VBufBackend_t::update() {
if(inUpdate) {
return;
}
inUpdate=true;
if(this->hasContent()) {
this->lock.acquire();
LOG_DEBUG(L"Updating "<<pendingInvalidSubtreesList.size()<<L" subtrees");
Expand Down Expand Up @@ -227,7 +223,6 @@ void VBufBackend_t::update() {
this->lock.release();
}
LOG_DEBUG(L"Update complete");
inUpdate=false;
}

void VBufBackend_t::terminate() {
Expand Down Expand Up @@ -278,13 +273,19 @@ VBufStorage_controlFieldNode_t* VBufBackend_t::reuseExistingNodeInRender(VBufSto
return nullptr;
}
if(existingNode->denyReuseIfPreviousSiblingsChanged) {
// This node is not allowed to be reused if any of its previous siblings have changed.
// We work this out by walking back to the previous controlFieldNode in its siblings, and ensuring that it is a reference node that references the existing node's first previous controlFieldNode.
// As we know that buffers are always rendered in a forward direction, we can garantee that if the previous controlFieldNode is correct,
// then all previous nodes before that are also correct.
VBufStorage_controlFieldNode_t* previousControlFieldNode=nullptr;
for(auto tempNode=previous;tempNode!=nullptr;tempNode=tempNode->getPrevious()) {
previousControlFieldNode=dynamic_cast<VBufStorage_controlFieldNode_t*>(tempNode);
if(previousControlFieldNode) break;
}
VBufStorage_referenceNode_t* previousReferenceNode=dynamic_cast<VBufStorage_referenceNode_t*>(previousControlFieldNode);
if(previousControlFieldNode&&!previousReferenceNode) {
// This is a controlFieldNode but not a referenceNode.
// Therefore this node has been newly added.
LOG_DEBUG(L"Previous controlFieldNode was not a referenceNode");
Copy link
Contributor

Choose a reason for hiding this comment

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

A comment here would be nice explaining that if the previous ControlFieldNode isn't a reference node, that means it is a newly added node.

return nullptr;
}
Expand All @@ -297,6 +298,9 @@ VBufStorage_controlFieldNode_t* VBufBackend_t::reuseExistingNodeInRender(VBufSto
if(previousExistingControlFieldNode) break;
}
if(previousControlFieldNode!=previousExistingControlFieldNode) {
// The previous node differs from the existing previous node.
// We already know its not because a node was added, therefore this must be either a removal or a move.
Copy link
Contributor

Choose a reason for hiding this comment

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

its -> it's

// either way, this means that the given node's previous siblings have changed.
LOG_DEBUG(L"Previous controlFieldNodes differ");
jcsteh marked this conversation as resolved.
Show resolved Hide resolved
return nullptr;
}
Expand Down
5 changes: 0 additions & 5 deletions nvdaHelper/vbufBase/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,6 @@ 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;

/**
* 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.
* If no content yet exists it renders the entire document. If content exists it only re-renders nodes marked as invalid.
Expand Down
2 changes: 1 addition & 1 deletion nvdaHelper/vbufBase/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class VBufStorage_controlFieldNode_t : public VBufStorage_fieldNode_t {
*/
bool alwaysRerenderChildren {false};

/*
/**
* If true, all this node's descendants will always be re-rendered along with this node when being re-rendered.
*/
bool alwaysRerenderDescendants {false};
Expand Down
2 changes: 1 addition & 1 deletion source/NVDAObjects/IAccessible/mozilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def _getPhysicalFocus(self):
def setFocus(self):
oldFocus=self._getPhysicalFocus()
super(Mozilla,self).setFocus()
# Although all versions of Firefox block in setFocus until the physical focus has moved,
# Although all versions of Firefox block inSetFocus or in accFocus until the physical focus has moved,
# Firefox 57 and above return before they fire a focus winEvent communicating the focus change to ATs.
# Therefore, If the call to setFocus did change the physical focus,
# Wait for a focus event to be queued to NVDA before returning.
Expand Down