Repository: nvaccess/nvda

Issue:
Screen reader announces table header twice for Angular 
<!--
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:

Using the table with sorting as documented here: https://material.angular.io/components/sort/overview

- Visit https://stackblitz.com/angular/xekbmvlqeqj?file=src%2Fapp%2Ftable-sorting-example.html
- Click open in new window to make navigation easier
- Navigate to the table header and activate it, (or click on it)

### Actual behavior:
NVDA reader announces the element twice as "Change sorting for name column 2 clickable Change sorting for name button"

### Expected behavior:
It announce the column once like "Change sorting for name column 2 clickable"

### System configuration

#### NVDA installed/portable/running from source:
installed

#### NVDA version:
2019.3.1

#### Windows version:
Windows 10

#### Name and version of other software in use when reproducing the issue:
Chrome Version 80.0.3987.122 (Official Build) (64-bit)

#### Other information about your system:

### 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.
No.


Discussion:
I don't seem to be able to reproduce this issue in firefox or chrome. Does this occur for you when you use keyboard only input? Have you tested firefox?
Yes Chrome and Firefox. Use the stackblitz link I posted:[ Stackblitz](https://stackblitz.com/angular/xekbmvlqeqj?file=src%2Fapp%2Ftable-sorting-example.html)
Still unable to reproduce the issue with Firefox 74.0
I can now reproduce the issue with Google Chrome 80.0.3987.132. I think chrome updated since my testing yesterday.

The issue is also reproducible with keyboard input.

This is only reproducible in focus mode when navigating with tab or shift+tab.
Quite possibly related, a much simpler test case: [code pen](https://codepen.io/reefturner/pen/oNzNNmv), and the [code pen full view](https://codepen.io/reefturner/full/oNzNNmv)

Resolving patch:
diff --git a/source/virtualBuffers/__init__.py b/source/virtualBuffers/__init__.py
--- a/source/virtualBuffers/__init__.py
+++ b/source/virtualBuffers/__init__.py
@@ -327,6 +327,10 @@ def _normalizeControlField(self, attrs: textInfos.ControlField):
 			# Get the text for the header cells.
 			textList = []
 			for docHandle, ID in cellIdentifiers:
+				if attrs.get("controlIdentifier_docHandle") == docHandle and attrs.get("controlIdentifier_ID") == ID:
+					# This is a self-reference to a column or row header
+					# Do not double up the cell header name. This is happening in Chrome.
+					continue
 				try:
 					start, end = self._getOffsetsFromFieldIdentifier(int(docHandle), int(ID))
 				except (LookupError, ValueError):


Test patch:
diff --git a/tests/system/robot/chromeTests.py b/tests/system/robot/chromeTests.py
--- a/tests/system/robot/chromeTests.py
+++ b/tests/system/robot/chromeTests.py
@@ -316,7 +316,7 @@ def test_ariaTreeGrid_browseMode():
 	actualSpeech = _chrome.getSpeechAfterKey("downArrow")
 	_asserts.strings_match(
 		actualSpeech,
-		"row 1  Subject  column 1  Subject"
+		"row 1  column 1  Subject"
 	)
 	# Navigate to row 2 column 1 with NVDA table navigation command
 	actualSpeech = _chrome.getSpeechAfterKey("control+alt+downArrow")
@@ -461,7 +461,7 @@ def test_tableInStyleDisplayTable():
 	actualSpeech = _chrome.getSpeechAfterKey("t")
 	_asserts.strings_match(
 		actualSpeech,
-		"table  with 2 rows and 2 columns  row 1  First heading  column 1  First heading"
+		"table  with 2 rows and 2 columns  row 1  column 1  First heading"
 	)
 	nextActualSpeech = _chrome.getSpeechAfterKey("control+alt+downArrow")
 	_asserts.strings_match(
@@ -603,3 +603,49 @@ def test_ariaDescription_sayAll():
 			"After Test Case Marker"
 		])
 	)
+
+
+def test_i10840():
+	"""
+	The name of table header cells should only be conveyed once when navigating directly to them in browse mode
+	Chrome self-references a header cell as its own header, which used to cause the name to be announced twice
+	"""
+	_chrome.prepareChrome(
+		f"""
+			<table>
+				<thead>
+					<tr>
+						<th>Month</th>
+						<th>items</th>
+					</tr>
+				</thead>
+				<tbody>
+					<tr>
+						<td>January</td>
+						<td>100</td>
+					</tr>
+					<tr>
+						<td>February</td>
+						<td>80</td>
+					</tr>
+				</tbody>
+				<tfoot>
+					<tr>
+						<td>Sum</td>
+						<td>180</td>
+					</tr>
+				</tfoot>
+				</table>
+		"""
+	)
+	# Jump to the table
+	actualSpeech = _chrome.getSpeechAfterKey("t")
+	_asserts.strings_match(
+		actualSpeech,
+		"table  with 4 rows and 2 columns  row 1  column 1  Month"
+	)
+	nextActualSpeech = _chrome.getSpeechAfterKey("control+alt+rightArrow")
+	_asserts.strings_match(
+		nextActualSpeech,
+		"column 2  items"
+	)
diff --git a/tests/system/robot/chromeTests.robot b/tests/system/robot/chromeTests.robot
--- a/tests/system/robot/chromeTests.robot
+++ b/tests/system/robot/chromeTests.robot
@@ -69,3 +69,6 @@ ARIA description Browse Mode
 ARIA description Say All
 	[Documentation]	Say all, contents includes aria-description
 	test_ariaDescription_sayAll
+i10840
+	[Documentation]	The name of table header cells should only be conveyed once when navigating directly to them in browse mode (chrome self-references a header cell as its own header, which used to cause the name to be announced twice)
+	test_i10840