Repository: nvaccess/nvda

Issue:
UIA: Reporting landmark shouldn't rely on localized landmark property
In Edge, NVDA relies on UIAHandler.UIA_LocalizedLandmarkTypePropertyId to retrieve landmark information. In Dutch, landmark translations are fairly poor. For example, main translates to vast, which back translates to fixed (as in fixed size). Reporting landmarks in Dutch breaks anyway.

There is also UIAHandler.UIA_LandmarkTypePropertyId. We might be able to use that instead?


Discussion:
Hi, is Microsoft aware of this? Thanks.

 

From: Leonard de Ruijter [mailto:notifications@github.com] 
Sent: Tuesday, June 27, 2017 9:15 AM
To: nvaccess/nvda <nvda@noreply.github.com>
Cc: Subscribed <subscribed@noreply.github.com>
Subject: [nvaccess/nvda] UIA: Reporting landmark shouldn't rely on localized landmark property (#7328)

 

In Edge, NVDA relies on UIAHandler.UIA_LocalizedLandmarkTypePropertyId to retrieve landmark information. In Dutch, landmark translations are fairly poor. For example, main translates to vast, which back translates to fixed (as in fixed size). Reporting landmarks in Dutch breaks anyway.

There is also UIAHandler.UIA_LandmarkTypePropertyId. We might be able to use that instead?

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <https://github.com/nvaccess/nvda/issues/7328> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AHgLkLwbOCK5cKbkavVDrzY4XgCfpe7aks5sISpngaJpZM4OG3Jw> .


@MichaelDCurran, any particular reason we use the localized property here? I'd argue it makes sense to be consistent with the landmark names used in other browsers (as specified in our aria module).

landMarkType only has a hand full of constants. I guess we should at least support the constants it does have. but from memory some pretty important ones are missing currently. If role is exposed via ariaProperties then we could also just use that.
But "main" isn't a role, or is it?

On Tue, Jun 27, 2017 at 8:55 PM, Michael Curran <notifications@github.com>
wrote:

> landMarkType only has a hand full of constants. I guess we should at least
> support the constants it does have. but from memory some pretty important
> ones are missing currently. If role is exposed via ariaProperties then we
> could also just use that.
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/nvaccess/nvda/issues/7328#issuecomment-311542971>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AFGivRYFRUfvVP5KjOMA-Q4EsMEtio8mks5sIcC0gaJpZM4OG3Jw>
> .
>



-- 

Derek Riemer: Improving the world one byte at a time!

   - University of Colorado Boulder Department of computer science, 4th
   year undergraduate student.
   - Accessibility enthusiast.
   - Proud user of the NVDA screen reader.
   - Open source enthusiast.
   - Skier.

Personal website <http://derekriemer.com>

> landMarkType only has a hand full of constants. I guess we should at least support the constants it does have. but from memory some pretty important ones are missing currently.

Banner, complementary and contentinfo are missing.
> If role is exposed via ariaProperties then we could also just use that.

It is. So we can just go the role way using aria properties, or use the excisting landmark constants and fallback to role for the landmarks which don't have a constant. Personally, I prefer the first approach.
So does LocalizedLandmark still work for the missing landmarks? And if so,
what does (non-localized) Landmark return in that case?

Note that we should still probably use LocalizedLandmark for quick nav,
since there can be multiple ARIA roles and I don't think there's a way to
do a token match with UIA conditions.

> So does LocalizedLandmark still work for the missing landmarks? 

Yes

> And if so, what does (non-localized) Landmark return in that case?

The number 80000, UIA_CustomLandmarkTypeId

> Note that we should still probably use LocalizedLandmark for quick nav, since there can be multiple ARIA roles and I don't think there's a way to do a token match with UIA conditions.

Sounds like we are on one line here.

Resolving patch:
diff --git a/source/NVDAObjects/UIA/__init__.py b/source/NVDAObjects/UIA/__init__.py
--- a/source/NVDAObjects/UIA/__init__.py
+++ b/source/NVDAObjects/UIA/__init__.py
@@ -73,7 +73,7 @@ def _get_controlFieldNVDAObjectClass(self):
 		UIAHandler.UIA_PositionInSetPropertyId,
 		UIAHandler.UIA_SizeOfSetPropertyId,
 		UIAHandler.UIA_AriaRolePropertyId,
-		UIAHandler.UIA_LocalizedLandmarkTypePropertyId,
+		UIAHandler.UIA_LandmarkTypePropertyId,
 		UIAHandler.UIA_AriaPropertiesPropertyId,
 		UIAHandler.UIA_LevelPropertyId,
 		UIAHandler.UIA_IsEnabledPropertyId,
diff --git a/source/NVDAObjects/UIA/edge.py b/source/NVDAObjects/UIA/edge.py
--- a/source/NVDAObjects/UIA/edge.py
+++ b/source/NVDAObjects/UIA/edge.py
@@ -1,8 +1,8 @@
-#A part of NonVisual Desktop Access (NVDA)
+#NVDAObjects/UIA/edge.py
 #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) 2015-2016 NV Access Limited
+#Copyright (C) 2015-2017 NV Access Limited, Babbage B.V.
 
 from comtypes import COMError
 from comtypes.automation import VARIANT
@@ -131,9 +131,7 @@ def _getControlFieldForObject(self,obj,isEmbedded=False,startOfNode=False,endOfN
 		field=super(EdgeTextInfo,self)._getControlFieldForObject(obj,isEmbedded=isEmbedded,startOfNode=startOfNode,endOfNode=endOfNode)
 		field['embedded']=isEmbedded
 		# report landmarks
-		landmark=obj._getUIACacheablePropertyValue(UIAHandler.UIA_LocalizedLandmarkTypePropertyId)
-		if landmark and (landmark!='region' or field.get('name')):
-			field['landmark']=aria.landmarkRoles.get(landmark)
+		field['landmark']=obj.landmark
 		# Combo boxes with a text pattern are editable
 		if obj.role==controlTypes.ROLE_COMBOBOX and obj.UIATextPattern:
 			field['states'].add(controlTypes.STATE_EDITABLE)
@@ -425,7 +423,9 @@ def _get_role(self):
 		role=super(EdgeNode,self).role
 		if not isinstance(self,EdgeHTMLRoot) and role==controlTypes.ROLE_PANE and self.UIATextPattern:
 			return controlTypes.ROLE_INTERNALFRAME
-		ariaRole=self._getUIACacheablePropertyValue(UIAHandler.UIA_AriaRolePropertyId)
+		ariaRole=self._getUIACacheablePropertyValue(UIAHandler.UIA_AriaRolePropertyId).lower()
+		# #7333: It is valid to provide multiple, space separated aria roles in HTML
+		# The role used is the first role in the list that has an associated NVDA role in aria.ariaRolesToNVDARoles
 		for ariaRole in ariaRole.split():
 			newRole=aria.ariaRolesToNVDARoles.get(ariaRole)
 			if newRole:
@@ -490,6 +490,19 @@ def _get__isTextEmpty(self):
 			return True
 		return False
 
+	def _get_landmark(self):
+		"""Fetches the aria landmark role for this object."""
+		landmarkId=self._getUIACacheablePropertyValue(UIAHandler.UIA_LandmarkTypePropertyId)
+		if not landmarkId: # will be 0 for non-landmarks
+			return None
+		ariaRoles=self._getUIACacheablePropertyValue(UIAHandler.UIA_AriaRolePropertyId).lower()
+		# #7333: It is valid to provide multiple, space separated aria roles in HTML
+		# If multiple roles or even multiple landmark roles are provided, the first one is used
+		for ariaRole in ariaRoles.split():
+			if ariaRole in aria.landmarkRoles and (ariaRole!='region' or self.name):
+				return ariaRole
+		return None
+
 class EdgeList(EdgeNode):
 
 	# non-focusable lists are readonly lists (ensures correct NVDA presentation category)
diff --git a/source/UIABrowseMode.py b/source/UIABrowseMode.py
--- a/source/UIABrowseMode.py
+++ b/source/UIABrowseMode.py
@@ -1,7 +1,7 @@
 #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) 2015-2016 NV Access Limited
+#Copyright (C) 2015-2017 NV Access Limited, Babbage B.V.
 
 from ctypes import byref
 from comtypes import COMError
@@ -15,6 +15,7 @@
 import textInfos
 import browseMode
 from NVDAObjects.UIA import UIA
+import aria
 
 class UIATextRangeQuickNavItem(browseMode.TextInfoQuickNavItem):
 
@@ -41,9 +42,7 @@ def obj(self):
 	def label(self):
 		if self.itemType=="landmark":
 			obj=self.obj
-			name=obj.name
-			landmarkType=obj.UIAElement.getCurrentPropertyValue(UIAHandler.UIA_LocalizedLandmarkTypePropertyId)
-			return " ".join(x for x in (name,landmarkType) if x)
+			return " ".join(x for x in (obj.name,aria.landmarkRoles.get(obj.landmark)) if x)
 		return super(UIATextRangeQuickNavItem,self).label
 
 class HeadingUIATextInfoQuickNavItem(browseMode.TextInfoQuickNavItem):
@@ -294,7 +293,7 @@ def _iterNodesByType(self,nodeType,direction="next",pos=None):
 			condition=createUIAMultiPropertyCondition({UIAHandler.UIA_ControlTypePropertyId:UIAHandler.UIA_EditControlTypeId,UIAHandler.UIA_ValueIsReadOnlyPropertyId:False},{UIAHandler.UIA_ControlTypePropertyId:UIAHandler.UIA_ListControlTypeId,UIAHandler.UIA_IsKeyboardFocusablePropertyId:True},{UIAHandler.UIA_ControlTypePropertyId:[UIAHandler.UIA_CheckBoxControlTypeId,UIAHandler.UIA_RadioButtonControlTypeId,UIAHandler.UIA_ComboBoxControlTypeId,UIAHandler.UIA_ButtonControlTypeId]})
 			return UIAControlQuicknavIterator(nodeType,self,pos,condition,direction)
 		elif nodeType=="landmark":
-			condition=UIAHandler.handler.clientObject.createNotCondition(UIAHandler.handler.clientObject.createPropertyCondition(UIAHandler.UIA_LocalizedLandmarkTypePropertyId,""))
+			condition=UIAHandler.handler.clientObject.createNotCondition(UIAHandler.handler.clientObject.createPropertyCondition(UIAHandler.UIA_LandmarkTypePropertyId,0))
 			return UIAControlQuicknavIterator(nodeType,self,pos,condition,direction)
 		elif nodeType=="nonTextContainer":
 			condition=createUIAMultiPropertyCondition({UIAHandler.UIA_ControlTypePropertyId:UIAHandler.UIA_ListControlTypeId,UIAHandler.UIA_IsKeyboardFocusablePropertyId:True},{UIAHandler.UIA_ControlTypePropertyId:UIAHandler.UIA_ComboBoxControlTypeId})


Test patch: