Repository: nvaccess/nvda

Issue:
NVDA seems to apply some kind of extra processing on label text before reading it
### Steps to reproduce:

I have a problem is with a combo box which holds a history of regular expressions in a Java application, NVDA does not properly read the text for each entry.
As an example I have a Java application which I'm running with the Java access bridge enabled:

    public static void main(String[] args) {
    JFrame fr = new JFrame("abc");
    fr.setSize(500, 500);
    JComboBox combo = new JComboBox(new String[] {"abc", "(<image[^>\\n]*)\\n([^>]*>)"});
    combo.setEditable(false);
    BasicComboBoxRenderer renderer = (BasicComboBoxRenderer) combo.getRenderer();
    renderer.putClientProperty( javax.swing.plaf.basic.BasicHTML.propertyKey, null);
    combo.putClientProperty( javax.swing.plaf.basic.BasicHTML.propertyKey, null);
    
    fr.getContentPane().add(combo, BorderLayout.CENTER);
     fr.setVisible(true);
    }

When I move the focus in the combo drop down list on the second entry NVDA should read "less than image square bracket....". But somehow it skips the content all the way to the first ">". So NVDA might to apply some kind of regular expression which removes what it considers to be "&lt;tags>" from the content before reading it.

### Actual behavior:
NVDA does not read the entire content of the "(<image[^>\\n]*)\\n([^>]*>)" value set on the label.

### Expected behavior:
NVDA should read the label content as it is, as the label is not HTML aware.

### System configuration
#### NVDA installed/portable/running from source:
Yes
#### NVDA version:
nvda_2019.3.1
#### Windows version:
10

### Other questions
#### Does the issue still occur after restarting your computer?
Yes
#### Have you tried any other versions of NVDA? If so, please report their behaviors.
No




Discussion:
Please retry this with the latest version of NVDA 2021.2. If the issue still persists it is possible that NVDA gets a wrong information from the Java app. To rule this out please inspect developer information for the combobox by pressing NVDA+F1 when it is focused.
Thanks @lukaszgo1 , here's what I tried on my side:

  - Downloaded and used NVDA 2021.2, problem persists
  - Downloaded and used JAWS 2021, with JAWS the combo box's list of items is properly read, even for the item which has the text description "(<image[^>\\n]*)\\n([^>]*>)".
  
I also added some logging on the Java side of things and the AccessibleContext specific for the combo box renderer properly returns the value of the item.

So for that particular item with the description "(<image[^>\\n]*)\\n([^>]*>)" JAWS reads "less image left bracket....." and NVDA reads "slash n right bracket" so NVDA skips over that entire "<image[^>" part as if it has a regular expression applied over the original content which tries to filter out `<tagName>`

Hello
I do not know so much about this issue.
However just reading this issue, I can see that some part of the template are missing or not filled correctly (did you test without add-ons? did you test on other NVDA versions? is NVDA installed/portable/run from source?)
Could you complete the issue template and also test with a newer version of NVDA (2021.2 or 2021.3beta2)?


@CyrilleB79 thanks for the interested, as I said in the reply above:

     Downloaded and used NVDA 2021.2, problem persists

So I tested with both NVDA 2019.3.1 and 2021.2 and I have the same problem. JAWS 2021 does not have this problem.
I have no idea what running NVDA without add-ons means, I just download NVDA from your web site and run it, in the dialog which shows I choose "Continue running" and use it like that.
The regular expression which strips simple tags from JAB objects has been introduced in 07d46dece52d708b3cf29ef25b3a346183f01a0f, and then expanded to handle comboboxes in 76c3482a91cbb89b648eae76784f763b8d585317. For the latter commit there is an issue #3755 which explains that JAB comboboxes can contain unneeded HTML tags which should be removed, but does not provide any examples. @michaelDCurran  I understand this code was written ages ago,, but if you would be able to recall specific examples of applications where tags indeed need to be removed that would be  most helpful. Also cc  @jcsteh  since the initial code was written by you.
@lukaszgo1 thanks for the investigation, for extra clarity about our use case adding a screenshot with the part of the application where the combo box item is encountered: <img width="608" alt="Screen Shot 2021-11-29 at 12 59 00" src="https://user-images.githubusercontent.com/1005979/143856188-bd4a6007-c033-4b64-b653-5b3926fa0d26.png">

So as the text to find can contain regular expressions, the recent used items may contain "<" and ">" and they need to be read by NVDA.

Image description for the screenshot: The screenshot is of a find & replace dialog. The focus is on a dropdown ComboBox, displaying the search history, where the focused item is `(<image[^>\\n]*)\\n([^>]*>)`.
My vague recollection is that some Swing controls (even in places like the
Java Control Panel) contained HTML in their labels/descriptions. I can't be
more specific than that, though.

@seanbudd thanks for providing the alternate description and sorry for not providing it myself.
@jcsteh yes some Java controls contain HTML content in labels, this one in particular has HTML content disabled, but even if the controls contain HTML content inside it would usually start and end with the &lt;html> tag.
I think first of all, I'd install the current version of nvda to the drive 
and then use that, so everyone is working from the same  system. There are 
sometimes oddities when you run it portably or just after the installer runs 
but does not install.
 Brian

***@***.***
Sent via blueyonder.
Please address personal E-mail to:-
***@***.***, putting 'Brian Gaff'
in the display name field.
Newsgroup monitored: alt.comp.blind-users
----- Original Message ----- 
From: "Radu Coravu" ***@***.***>
To: "nvaccess/nvda" ***@***.***>
Cc: "Subscribed" ***@***.***>
Sent: Monday, November 29, 2021 11:01 AM
Subject: Re: [nvaccess/nvda] NVDA seems to apply some kind of extra 
processing on label text before reading it (Issue #13102)


> @lukaszgo1 thanks for the investigation, for extra clarity about our use 
> case adding a screenshot with the part of the application where the combo 
> box item is encountered: <img width="608" alt="Screen Shot 2021-11-29 at 
> 12 59 00" 
> src="https://user-images.githubusercontent.com/1005979/143856188-bd4a6007-c033-4b64-b653-5b3926fa0d26.png">
>
> So as the text to find can contain regular expressions, the recent used 
> items may contain "<" and ">" and they need to be read by NVDA.
>
>
> -- 
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly or view it on GitHub:
> https://github.com/nvaccess/nvda/issues/13102#issuecomment-981526098 


@Brian1Gaff I have the same problem with the latest NVDA snapshot I tested (Thu Dec  2 03:05:33 2021)
Looking at the Oracle Java docs, it seems like for labels, buttons, check boxes and various other Java swing controls the way to define that the content contains HTML is to include a &lt;html&gt; tag at the start of the text.
https://docs.oracle.com/javase/tutorial/uiswing/components/html.html
I looked through the JLabel documentation and there is no API functions for discovering whether the label contains HTML, so it seems like the html tag is the way to detect it.
So I would suggest rather than just looking for any tag which may be html, NVDA should look if the text starts with the html tag and only then strip out tags and process escape sequences for &lt; and &gt; and other HTML character escape sequences.
@mwhapples I agree with the proposed change. This would work in most cases.

Resolving patch:
diff --git a/source/NVDAObjects/JAB/__init__.py b/source/NVDAObjects/JAB/__init__.py
--- a/source/NVDAObjects/JAB/__init__.py
+++ b/source/NVDAObjects/JAB/__init__.py
@@ -97,6 +97,12 @@
 
 re_simpleXmlTag=re.compile(r"\<[^>]+\>")
 
+
+def _processHtml(text):
+	""" Strips HTML tags from text if it is HTML """
+	return re_simpleXmlTag.sub(" ", text) if text.startswith("<html>") else text
+
+
 class JABTextInfo(textInfos.offsets.OffsetsTextInfo):
 
 	def _getOffsetFromPoint(self,x,y):
@@ -274,7 +280,8 @@ def _get_keyboardShortcut(self):
 		return ", ".join(shortcutsList)
 
 	def _get_name(self):
-		return re_simpleXmlTag.sub(" ", self._JABAccContextInfo.name)
+		name = self._JABAccContextInfo.name
+		return _processHtml(name)
 
 	def _get_JABRole(self):
 		return self._JABAccContextInfo.role_en_US
@@ -315,7 +322,8 @@ def _get_value(self):
 			return self.jabContext.getCurrentAccessibleValueFromContext()
 
 	def _get_description(self):
-		return re_simpleXmlTag.sub(" ", self._JABAccContextInfo.description)
+		description = self._JABAccContextInfo.description
+		return _processHtml(description)
 
 	def _get_location(self):
 		return RectLTWH(self._JABAccContextInfo.x,self._JABAccContextInfo.y,self._JABAccContextInfo.width,self._JABAccContextInfo.height)
@@ -548,6 +556,7 @@ def event_gainFocus(self):
 		if activeDescendant:
 			eventHandler.queueEvent("gainFocus",activeDescendant)
 
+
 class ComboBox(JAB):
 
 	def _get_states(self):


Test patch:
diff --git a/tests/unit/test_javaAccessBridge.py b/tests/unit/test_javaAccessBridge.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_javaAccessBridge.py
@@ -0,0 +1,28 @@
+# A part of NonVisual Desktop Access (NVDA)
+# This file is covered by the GNU General Public License.
+# See the file COPYING for more details.
+# Copyright (C) 2022 NV Access Limited, American Printing House for the Blind
+
+"""Unit tests for Java Access Bridge"""
+
+import unittest
+from NVDAObjects import JAB
+
+
+class TestJavaAccessBridge(unittest.TestCase):
+	def test_plainTextNotModified(self):
+		plainText = "Some plain text with no HTML tags."
+		self.assertEqual(plainText, JAB._processHtml(plainText))
+
+	def test_plainTextWithTagsNotModified(self):
+		plainText = "<p>some <b>text</b>.</p>"
+		self.assertEqual(plainText, JAB._processHtml(plainText))
+
+	def test_regexNotModified(self):
+		regexStr = "(<image[^>\\n]*)\\n([^>]*>)"
+		self.assertEqual(regexStr, JAB._processHtml(regexStr))
+
+	def test_htmlStringHasTagsRemoved(self):
+		htmlStr = "<html><body><p>Some <b>bold</b> text.</p></body></html>"
+		expected = "   Some  bold  text.   "
+		self.assertEqual(expected, JAB._processHtml(htmlStr))