Repository: nvaccess/nvda

Issue:
Browse mode: reading wrong next focusable element if the previous focusable element is changed from display block to none
<!--
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
-->

### Steps to reproduce: Firefox + NVDA
[Firefox+NVDA weired reading while InfoBubble followed by a focusable element (open in Firefox).txt](https://github.com/nvaccess/nvda/files/3694877/Firefox%2BNVDA.weired.reading.while.InfoBubble.followed.by.a.focusable.element.open.in.Firefox.txt)
1. Open the attach file in Firefox.
2. Tabbing through the page until a info bubble shows. The info bubble contains a long text that  NVDA will split the text into three part while in browse mode (arrow down to read the text).
![image](https://user-images.githubusercontent.com/56236027/66276333-84d71e00-e857-11e9-8df0-b89a4b479d79.png)
3. Keep arrow down until the infobubble fade.
4. At this time the focus should be on "Dan Jian" focusable span element. However, NVDA read the "Designate one or more..." focusable element instead.
![image](https://user-images.githubusercontent.com/56236027/66276372-062eb080-e858-11e9-953e-b197ed59ba89.png)

The interested thing is this issue won't be able to reproduce on jsfiddler and codepen, which we suspect it's because of the iframe. The issue won't occur if the infobubble is rendered within an anchor element.

### Actual behavior: instead of reading the current focused element, NVDA reads something later on the page. 

### Expected behavior: Read the current focused element.

### System configuration
#### NVDA installed/portable/running from source: Installed.

#### NVDA version: 2018.4.1 and later. The issue first revealed in version 2019.1.1.

#### Windows version: Windows 10

#### Name and version of other software in use when reproducing the issue: Firefox - 67.0.4 

#### Other information about your system: N/A

### Other questions
#### Does the issue still occur after restarting your PC? Yes.

#### Have you tried any other versions of NVDA? If so, please report their behaviors. 
Tried the older version of NVDA 2018.3.2. The issue doesn't occur.





Discussion:
cc @jcsteh 
cc: @MarcoZehe 
Confirmed, however, this only affects speech. Braille is immediately focused on the correct span element.
Reproduced with NVDA 2019.3 alpha and Firefox 71 Nightly, so this is nothing that is adversely affected by our big changes in Firefox 70.

Resolving patch:
diff --git a/source/browseMode.py b/source/browseMode.py
--- a/source/browseMode.py
+++ b/source/browseMode.py
@@ -408,9 +408,12 @@ def _quickNavScript(self,gesture, itemType, direction, errorMessage, readUnit):
 		except StopIteration:
 			ui.message(errorMessage)
 			return
-		item.moveTo()
+		# #8831: Report before moving because moving might change the focus, which
+		# might mutate the document, potentially invalidating info if it is
+		# offset-based.
 		if not gesture or not willSayAllResume(gesture):
 			item.report(readUnit=readUnit)
+		item.moveTo()
 
 	@classmethod
 	def addQuickNav(cls, itemType, key, nextDoc, nextError, prevDoc, prevError, readUnit=None):
diff --git a/source/cursorManager.py b/source/cursorManager.py
--- a/source/cursorManager.py
+++ b/source/cursorManager.py
@@ -142,11 +142,15 @@ def _caretMovementScriptHelper(self,gesture,unit,direction=None,posConstant=text
 					pass
 				else:
 					info=self.makeTextInfo(textInfos.POSITION_FIRST if direction>0 else textInfos.POSITION_LAST)
-		self.selection=info
+		# #10343: Speak before setting selection because setting selection might
+		# move the focus, which might mutate the document, potentially invalidating
+		# info if it is offset-based.
+		selection = info.copy()
 		info.expand(unit)
 		if not willSayAllResume(gesture): speech.speakTextInfo(info,unit=unit,reason=controlTypes.REASON_CARET)
 		if not oldInfo.isCollapsed:
 			speech.speakSelectionChange(oldInfo,self.selection)
+		self.selection = selection
 
 	def doFindText(self,text,reverse=False,caseSensitive=False):
 		if not text:


Test patch: