prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Chrome: "list" is reported on every line of a list in rich text editors
  ### Steps to reproduce:
  1. Open this URL in Chrome:
      `data:text/html,<div contentEditable="true" role="textbox" aria-multiline="true">Before<ul><li>a</li><li>b</li></ul>After</div>`
  2. Focus the text box and ensure you are in focus mode.
  3. Press control+home.
  4. Read through the content line by line using the down arrow key.
  
  ### Expected behavior:
  ```
  Before
  list  bullet  a
  bullet  b
  out of list  After
  ```
  
  ### Actual behavior:
  ```
  Before
  list  bullet  a
  list  bullet  b
  After
  ```
  
  Note: Whether you hear "bullet" depends on your symbol level; I have mine set to "all".
  
  ### System configuration:
  NVDA version: next-14373,6bbe5915
  NVDA Installed or portable: installed
  Windows version: Windows 10 Version 1703 (OS Build 16251.0)
  Name and version of other software in use when reproducing the issue: Chrome Version 62.0.3201.2 (Official Build) canary (64-bit)
  
  ### Technical info:
  This happens because a contentEditable list (the `ul` tag) does not get the read-only state. Lists and list boxes both get the same role (list), but they're normally differentiated by the read-only state; a `<ul>` has read-only, whereas a `<select size="2">` doesn't. However, in this case, I can kinda understand why Chrome doesn't set read-only; after all, it does have the editable state.
  
  I think we should probably just tweak `TextInfo.getPresentationCategory` to treat editable liss as being containers; i.e. allow for the editable state as well as the read-only state in the rule for `PRESCAT_CONTAINER`. Alternatively, we could file a bug against Chrome requesting this get fixed on their side.
  
  P2 because this is quite annoying when dealing with rich text editors in Chrome, including the Gmail composer.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `source/NVDAObjects/IAccessible/chromium.py`
  Content:
  ```
  1 #NVDAObjects/IAccessible/chromium.py
  2 #A part of NonVisual Desktop Access (NVDA)
  3 #This file is covered by the GNU General Public License.
  4 #See the file COPYING for more details.
  5 # Copyright (C) 2010-2013 NV Access Limited
  6 
  7 """NVDAObjects for the Chromium browser project
  8 """
  9 
  10 from comtypes import COMError
  11 import oleacc
  12 import controlTypes
  13 import IAccessibleHandler
  14 from NVDAObjects.IAccessible import IAccessible
  15 from virtualBuffers.gecko_ia2 import Gecko_ia2 as GeckoVBuf, Gecko_ia2_TextInfo as GeckoVBufTextInfo
  16 from . import ia2Web
  17 
  18 
  19 class ChromeVBufTextInfo(GeckoVBufTextInfo):
  20 
  21 	def _normalizeControlField(self, attrs):
  22 		attrs = super()._normalizeControlField(attrs)
  23 		if attrs['role'] == controlTypes.ROLE_TOGGLEBUTTON and controlTypes.STATE_CHECKABLE in attrs['states']:
  24 			# In Chromium, the checkable state is exposed erroneously on toggle buttons.
  25 			attrs['states'].discard(controlTypes.STATE_CHECKABLE)
  26 		return attrs
  27 
  28 
  29 class ChromeVBuf(GeckoVBuf):
  30 	TextInfo = ChromeVBufTextInfo
  31 
  32 	def __contains__(self, obj):
  33 		if obj.windowHandle != self.rootNVDAObject.windowHandle:
  34 			return False
  35 		if not isinstance(obj,ia2Web.Ia2Web):
  36 			# #4080: Input composition NVDAObjects are the same window but not IAccessible2!
  37 			return False
  38 		accId = obj.IA2UniqueID
  39 		if accId == self.rootID:
  40 			return True
  41 		try:
  42 			self.rootNVDAObject.IAccessibleObject.accChild(accId)
  43 		except COMError:
  44 			return False
  45 		return not self._isNVDAObjectInApplication(obj)
  46 
  47 
  48 class Document(ia2Web.Document):
  49 
  50 	def _get_treeInterceptorClass(self):
  51 		states = self.states
  52 		if controlTypes.STATE_EDITABLE not in states and controlTypes.STATE_BUSY not in states:
  53 			return ChromeVBuf
  54 		return super(Document, self).treeInterceptorClass
  55 
  56 class ComboboxListItem(IAccessible):
  57 	"""
  58 	Represents a list item inside a combo box.
  59 	"""
  60 
  61 	def _get_focusRedirect(self):
  62 		# Chrome 68 and below fires focus on the active list item of combo boxes even when the combo box is collapsed.
  63 		# We get around this by redirecting focus back up to the combo box itself if the list inside is invisible (I.e. the combo box is collapsed).
  64 		if self.parent and controlTypes.STATE_INVISIBLE in self.parent.states:
  65 			return self.parent.parent
  66 
  67 
  68 class ToggleButton(ia2Web.Ia2Web):
  69 
  70 	def _get_states(self):
  71 		# In Chromium, the checkable state is exposed erroneously on toggle buttons.
  72 		states = super().states
  73 		states.discard(controlTypes.STATE_CHECKABLE)
  74 		return states
  75 
  76 
  77 def findExtraOverlayClasses(obj, clsList):
  78 	"""Determine the most appropriate class(es) for Chromium objects.
  79 	This works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method.
  80 	"""
  81 	if obj.role==controlTypes.ROLE_LISTITEM and obj.parent and obj.parent.parent and obj.parent.parent.role==controlTypes.ROLE_COMBOBOX:
  82 		clsList.append(ComboboxListItem)
  83 	elif obj.role == controlTypes.ROLE_TOGGLEBUTTON:
  84 		clsList.append(ToggleButton)
  85 	ia2Web.findExtraOverlayClasses(obj, clsList,
  86 		documentClass=Document)
  87
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/source/NVDAObjects/IAccessible/chromium.py b/source/NVDAObjects/IAccessible/chromium.py
  --- a/source/NVDAObjects/IAccessible/chromium.py
  +++ b/source/NVDAObjects/IAccessible/chromium.py
  @@ -74,6 +74,22 @@
   		return states
   
   
  +class PresentationalList(ia2Web.Ia2Web):
  +	"""
  +	Ensures that lists like UL, DL and OL always have the readonly state.
  +	A work-around for issue #7562
  +	allowing us to differentiate presentational lists from interactive lists
  +	(such as of size greater 1 and ARIA list boxes).
  +	In firefox, this is possible by the presence of a read-only state,
  +	even in a content editable.
  +	"""
  +
  +	def _get_states(self):
  +		states = super().states
  +		states.add(controlTypes.STATE_READONLY)
  +		return states
  +
  +
   def findExtraOverlayClasses(obj, clsList):
   	"""Determine the most appropriate class(es) for Chromium objects.
   	This works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method.
  @@ -82,5 +98,7 @@
   		clsList.append(ComboboxListItem)
   	elif obj.role == controlTypes.ROLE_TOGGLEBUTTON:
   		clsList.append(ToggleButton)
  +	elif obj.role == controlTypes.ROLE_LIST and obj.IA2Attributes.get('tag') in ('ul', 'dl', 'ol'):
  +		clsList.append(PresentationalList)
   	ia2Web.findExtraOverlayClasses(obj, clsList,
   		documentClass=Document)
  
verification_info: {"golden_diff": "diff --git a/source/NVDAObjects/IAccessible/chromium.py b/source/NVDAObjects/IAccessible/chromium.py\n--- a/source/NVDAObjects/IAccessible/chromium.py\n+++ b/source/NVDAObjects/IAccessible/chromium.py\n@@ -74,6 +74,22 @@\n \t\treturn states\r\n \r\n \r\n+class PresentationalList(ia2Web.Ia2Web):\r\n+\t\"\"\"\r\n+\tEnsures that lists like UL, DL and OL always have the readonly state.\r\n+\tA work-around for issue #7562\r\n+\tallowing us to differentiate presentational lists from interactive lists\r\n+\t(such as of size greater 1 and ARIA list boxes).\r\n+\tIn firefox, this is possible by the presence of a read-only state,\r\n+\teven in a content editable.\r\n+\t\"\"\"\r\n+\r\n+\tdef _get_states(self):\r\n+\t\tstates = super().states\r\n+\t\tstates.add(controlTypes.STATE_READONLY)\r\n+\t\treturn states\r\n+\r\n+\r\n def findExtraOverlayClasses(obj, clsList):\r\n \t\"\"\"Determine the most appropriate class(es) for Chromium objects.\r\n \tThis works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method.\r\n@@ -82,5 +98,7 @@\n \t\tclsList.append(ComboboxListItem)\r\n \telif obj.role == controlTypes.ROLE_TOGGLEBUTTON:\r\n \t\tclsList.append(ToggleButton)\r\n+\telif obj.role == controlTypes.ROLE_LIST and obj.IA2Attributes.get('tag') in ('ul', 'dl', 'ol'):\r\n+\t\tclsList.append(PresentationalList)\r\n \tia2Web.findExtraOverlayClasses(obj, clsList,\r\n \t\tdocumentClass=Document)\n", "issue": "Chrome: \"list\" is reported on every line of a list in rich text editors\n### Steps to reproduce:\r\n1. Open this URL in Chrome:\r\n    `data:text/html,<div contentEditable=\"true\" role=\"textbox\" aria-multiline=\"true\">Before<ul><li>a</li><li>b</li></ul>After</div>`\r\n2. Focus the text box and ensure you are in focus mode.\r\n3. Press control+home.\r\n4. Read through the content line by line using the down arrow key.\r\n\r\n### Expected behavior:\r\n```\r\nBefore\r\nlist  bullet  a\r\nbullet  b\r\nout of list  After\r\n```\r\n\r\n### Actual behavior:\r\n```\r\nBefore\r\nlist  bullet  a\r\nlist  bullet  b\r\nAfter\r\n```\r\n\r\nNote: Whether you hear \"bullet\" depends on your symbol level; I have mine set to \"all\".\r\n\r\n### System configuration:\r\nNVDA version: next-14373,6bbe5915\r\nNVDA Installed or portable: installed\r\nWindows version: Windows 10 Version 1703 (OS Build 16251.0)\r\nName and version of other software in use when reproducing the issue: Chrome Version 62.0.3201.2 (Official Build) canary (64-bit)\r\n\r\n### Technical info:\r\nThis happens because a contentEditable list (the `ul` tag) does not get the read-only state. Lists and list boxes both get the same role (list), but they're normally differentiated by the read-only state; a `<ul>` has read-only, whereas a `<select size=\"2\">` doesn't. However, in this case, I can kinda understand why Chrome doesn't set read-only; after all, it does have the editable state.\r\n\r\nI think we should probably just tweak `TextInfo.getPresentationCategory` to treat editable liss as being containers; i.e. allow for the editable state as well as the read-only state in the rule for `PRESCAT_CONTAINER`. Alternatively, we could file a bug against Chrome requesting this get fixed on their side.\r\n\r\nP2 because this is quite annoying when dealing with rich text editors in Chrome, including the Gmail composer.\n", "before_files": [{"content": "#NVDAObjects/IAccessible/chromium.py\r\n#A part of NonVisual Desktop Access (NVDA)\r\n#This file is covered by the GNU General Public License.\r\n#See the file COPYING for more details.\r\n# Copyright (C) 2010-2013 NV Access Limited\r\n\r\n\"\"\"NVDAObjects for the Chromium browser project\r\n\"\"\"\r\n\r\nfrom comtypes import COMError\r\nimport oleacc\r\nimport controlTypes\r\nimport IAccessibleHandler\r\nfrom NVDAObjects.IAccessible import IAccessible\r\nfrom virtualBuffers.gecko_ia2 import Gecko_ia2 as GeckoVBuf, Gecko_ia2_TextInfo as GeckoVBufTextInfo\r\nfrom . import ia2Web\r\n\r\n\r\nclass ChromeVBufTextInfo(GeckoVBufTextInfo):\r\n\r\n\tdef _normalizeControlField(self, attrs):\r\n\t\tattrs = super()._normalizeControlField(attrs)\r\n\t\tif attrs['role'] == controlTypes.ROLE_TOGGLEBUTTON and controlTypes.STATE_CHECKABLE in attrs['states']:\r\n\t\t\t# In Chromium, the checkable state is exposed erroneously on toggle buttons.\r\n\t\t\tattrs['states'].discard(controlTypes.STATE_CHECKABLE)\r\n\t\treturn attrs\r\n\r\n\r\nclass ChromeVBuf(GeckoVBuf):\r\n\tTextInfo = ChromeVBufTextInfo\r\n\r\n\tdef __contains__(self, obj):\r\n\t\tif obj.windowHandle != self.rootNVDAObject.windowHandle:\r\n\t\t\treturn False\r\n\t\tif not isinstance(obj,ia2Web.Ia2Web):\r\n\t\t\t# #4080: Input composition NVDAObjects are the same window but not IAccessible2!\r\n\t\t\treturn False\r\n\t\taccId = obj.IA2UniqueID\r\n\t\tif accId == self.rootID:\r\n\t\t\treturn True\r\n\t\ttry:\r\n\t\t\tself.rootNVDAObject.IAccessibleObject.accChild(accId)\r\n\t\texcept COMError:\r\n\t\t\treturn False\r\n\t\treturn not self._isNVDAObjectInApplication(obj)\r\n\r\n\r\nclass Document(ia2Web.Document):\r\n\r\n\tdef _get_treeInterceptorClass(self):\r\n\t\tstates = self.states\r\n\t\tif controlTypes.STATE_EDITABLE not in states and controlTypes.STATE_BUSY not in states:\r\n\t\t\treturn ChromeVBuf\r\n\t\treturn super(Document, self).treeInterceptorClass\r\n\r\nclass ComboboxListItem(IAccessible):\r\n\t\"\"\"\r\n\tRepresents a list item inside a combo box.\r\n\t\"\"\"\r\n\r\n\tdef _get_focusRedirect(self):\r\n\t\t# Chrome 68 and below fires focus on the active list item of combo boxes even when the combo box is collapsed.\r\n\t\t# We get around this by redirecting focus back up to the combo box itself if the list inside is invisible (I.e. the combo box is collapsed).\r\n\t\tif self.parent and controlTypes.STATE_INVISIBLE in self.parent.states:\r\n\t\t\treturn self.parent.parent\r\n\r\n\r\nclass ToggleButton(ia2Web.Ia2Web):\r\n\r\n\tdef _get_states(self):\r\n\t\t# In Chromium, the checkable state is exposed erroneously on toggle buttons.\r\n\t\tstates = super().states\r\n\t\tstates.discard(controlTypes.STATE_CHECKABLE)\r\n\t\treturn states\r\n\r\n\r\ndef findExtraOverlayClasses(obj, clsList):\r\n\t\"\"\"Determine the most appropriate class(es) for Chromium objects.\r\n\tThis works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method.\r\n\t\"\"\"\r\n\tif obj.role==controlTypes.ROLE_LISTITEM and obj.parent and obj.parent.parent and obj.parent.parent.role==controlTypes.ROLE_COMBOBOX:\r\n\t\tclsList.append(ComboboxListItem)\r\n\telif obj.role == controlTypes.ROLE_TOGGLEBUTTON:\r\n\t\tclsList.append(ToggleButton)\r\n\tia2Web.findExtraOverlayClasses(obj, clsList,\r\n\t\tdocumentClass=Document)\r\n", "path": "source/NVDAObjects/IAccessible/chromium.py"}], "after_files": [{"content": "#NVDAObjects/IAccessible/chromium.py\r\n#A part of NonVisual Desktop Access (NVDA)\r\n#This file is covered by the GNU General Public License.\r\n#See the file COPYING for more details.\r\n# Copyright (C) 2010-2013 NV Access Limited\r\n\r\n\"\"\"NVDAObjects for the Chromium browser project\r\n\"\"\"\r\n\r\nfrom comtypes import COMError\r\nimport oleacc\r\nimport controlTypes\r\nimport IAccessibleHandler\r\nfrom NVDAObjects.IAccessible import IAccessible\r\nfrom virtualBuffers.gecko_ia2 import Gecko_ia2 as GeckoVBuf, Gecko_ia2_TextInfo as GeckoVBufTextInfo\r\nfrom . import ia2Web\r\n\r\n\r\nclass ChromeVBufTextInfo(GeckoVBufTextInfo):\r\n\r\n\tdef _normalizeControlField(self, attrs):\r\n\t\tattrs = super()._normalizeControlField(attrs)\r\n\t\tif attrs['role'] == controlTypes.ROLE_TOGGLEBUTTON and controlTypes.STATE_CHECKABLE in attrs['states']:\r\n\t\t\t# In Chromium, the checkable state is exposed erroneously on toggle buttons.\r\n\t\t\tattrs['states'].discard(controlTypes.STATE_CHECKABLE)\r\n\t\treturn attrs\r\n\r\n\r\nclass ChromeVBuf(GeckoVBuf):\r\n\tTextInfo = ChromeVBufTextInfo\r\n\r\n\tdef __contains__(self, obj):\r\n\t\tif obj.windowHandle != self.rootNVDAObject.windowHandle:\r\n\t\t\treturn False\r\n\t\tif not isinstance(obj,ia2Web.Ia2Web):\r\n\t\t\t# #4080: Input composition NVDAObjects are the same window but not IAccessible2!\r\n\t\t\treturn False\r\n\t\taccId = obj.IA2UniqueID\r\n\t\tif accId == self.rootID:\r\n\t\t\treturn True\r\n\t\ttry:\r\n\t\t\tself.rootNVDAObject.IAccessibleObject.accChild(accId)\r\n\t\texcept COMError:\r\n\t\t\treturn False\r\n\t\treturn not self._isNVDAObjectInApplication(obj)\r\n\r\n\r\nclass Document(ia2Web.Document):\r\n\r\n\tdef _get_treeInterceptorClass(self):\r\n\t\tstates = self.states\r\n\t\tif controlTypes.STATE_EDITABLE not in states and controlTypes.STATE_BUSY not in states:\r\n\t\t\treturn ChromeVBuf\r\n\t\treturn super(Document, self).treeInterceptorClass\r\n\r\nclass ComboboxListItem(IAccessible):\r\n\t\"\"\"\r\n\tRepresents a list item inside a combo box.\r\n\t\"\"\"\r\n\r\n\tdef _get_focusRedirect(self):\r\n\t\t# Chrome 68 and below fires focus on the active list item of combo boxes even when the combo box is collapsed.\r\n\t\t# We get around this by redirecting focus back up to the combo box itself if the list inside is invisible (I.e. the combo box is collapsed).\r\n\t\tif self.parent and controlTypes.STATE_INVISIBLE in self.parent.states:\r\n\t\t\treturn self.parent.parent\r\n\r\n\r\nclass ToggleButton(ia2Web.Ia2Web):\r\n\r\n\tdef _get_states(self):\r\n\t\t# In Chromium, the checkable state is exposed erroneously on toggle buttons.\r\n\t\tstates = super().states\r\n\t\tstates.discard(controlTypes.STATE_CHECKABLE)\r\n\t\treturn states\r\n\r\n\r\nclass PresentationalList(ia2Web.Ia2Web):\r\n\t\"\"\"\r\n\tEnsures that lists like UL, DL and OL always have the readonly state.\r\n\tA work-around for issue #7562\r\n\tallowing us to differentiate presentational lists from interactive lists\r\n\t(such as of size greater 1 and ARIA list boxes).\r\n\tIn firefox, this is possible by the presence of a read-only state,\r\n\teven in a content editable.\r\n\t\"\"\"\r\n\r\n\tdef _get_states(self):\r\n\t\tstates = super().states\r\n\t\tstates.add(controlTypes.STATE_READONLY)\r\n\t\treturn states\r\n\r\n\r\ndef findExtraOverlayClasses(obj, clsList):\r\n\t\"\"\"Determine the most appropriate class(es) for Chromium objects.\r\n\tThis works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method.\r\n\t\"\"\"\r\n\tif obj.role==controlTypes.ROLE_LISTITEM and obj.parent and obj.parent.parent and obj.parent.parent.role==controlTypes.ROLE_COMBOBOX:\r\n\t\tclsList.append(ComboboxListItem)\r\n\telif obj.role == controlTypes.ROLE_TOGGLEBUTTON:\r\n\t\tclsList.append(ToggleButton)\r\n\telif obj.role == controlTypes.ROLE_LIST and obj.IA2Attributes.get('tag') in ('ul', 'dl', 'ol'):\r\n\t\tclsList.append(PresentationalList)\r\n\tia2Web.findExtraOverlayClasses(obj, clsList,\r\n\t\tdocumentClass=Document)\r\n", "path": "source/NVDAObjects/IAccessible/chromium.py"}]}