Skip to content

Commit 7f60feb

Browse files
authored
Merge 49bdb0c into 90dd4e9
2 parents 90dd4e9 + 49bdb0c commit 7f60feb

12 files changed

Lines changed: 1162 additions & 675 deletions

File tree

source/NVDAObjects/UIA/__init__.py

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -647,21 +647,41 @@ def _getTextWithFieldsForUIARange(self,rootElement,textRange,formatConfig,includ
647647
if debug:
648648
log.debug("NULL childRange. Skipping")
649649
continue
650-
clippedStart=clippedEnd=False
651-
if index==lastChildIndex and childRange.CompareEndpoints(UIAHandler.TextPatternRangeEndpoint_Start,textRange,UIAHandler.TextPatternRangeEndpoint_End)>=0:
650+
clippedStart = False
651+
clippedEnd = False
652+
if childRange.CompareEndpoints(
653+
UIAHandler.TextPatternRangeEndpoint_End,
654+
textRange,
655+
UIAHandler.TextPatternRangeEndpoint_Start
656+
) <= 0:
657+
if debug:
658+
log.debug("Child completely before textRange. Skipping")
659+
continue
660+
if childRange.CompareEndpoints(
661+
UIAHandler.TextPatternRangeEndpoint_Start,
662+
textRange,
663+
UIAHandler.TextPatternRangeEndpoint_End
664+
) >= 0:
652665
if debug:
653666
log.debug("Child at or past end of textRange. Breaking")
654667
break
655-
if index==lastChildIndex:
656-
lastChildEndDelta=childRange.CompareEndpoints(UIAHandler.TextPatternRangeEndpoint_End,textRange,UIAHandler.TextPatternRangeEndpoint_End)
657-
if lastChildEndDelta>0:
658-
if debug:
659-
log.debug(
660-
"textRange ended part way through the child. "
661-
"Crop end of childRange to fit"
662-
)
663-
childRange.MoveEndpointByRange(UIAHandler.TextPatternRangeEndpoint_End,textRange,UIAHandler.TextPatternRangeEndpoint_End)
664-
clippedEnd=True
668+
lastChildEndDelta = childRange.CompareEndpoints(
669+
UIAHandler.TextPatternRangeEndpoint_End,
670+
textRange,
671+
UIAHandler.TextPatternRangeEndpoint_End
672+
)
673+
if lastChildEndDelta > 0:
674+
if debug:
675+
log.debug(
676+
"textRange ended part way through the child. "
677+
"Crop end of childRange to fit"
678+
)
679+
childRange.MoveEndpointByRange(
680+
UIAHandler.TextPatternRangeEndpoint_End,
681+
textRange,
682+
UIAHandler.TextPatternRangeEndpoint_End
683+
)
684+
clippedEnd = True
665685
childStartDelta=childRange.CompareEndpoints(UIAHandler.TextPatternRangeEndpoint_Start,tempRange,UIAHandler.TextPatternRangeEndpoint_End)
666686
if childStartDelta>0:
667687
# plain text before this child
@@ -880,23 +900,50 @@ def findOverlayClasses(self,clsList):
880900
# But not for Internet Explorer
881901
and not self.appModule.appName == 'iexplore'
882902
):
883-
from . import edge
903+
from . import spartan_edge
884904
if UIAClassName in ("Internet Explorer_Server","WebView") and self.role==controlTypes.ROLE_PANE:
885-
clsList.append(edge.EdgeHTMLRootContainer)
886-
elif (self.UIATextPattern and
887-
# #6998: Edge normally gives its root node a controlType of pane, but ARIA role="document" changes the controlType to document
888-
self.role in (controlTypes.ROLE_PANE,controlTypes.ROLE_DOCUMENT) and
889-
self.parent and (isinstance(self.parent,edge.EdgeHTMLRootContainer) or not isinstance(self.parent,edge.EdgeNode))
905+
clsList.append(spartan_edge.EdgeHTMLRootContainer)
906+
elif (
907+
self.UIATextPattern
908+
# #6998:
909+
# Edge normally gives its root node a controlType of pane, but ARIA role="document"
910+
# changes the controlType to document
911+
and self.role in (
912+
controlTypes.ROLE_PANE,
913+
controlTypes.ROLE_DOCUMENT
914+
)
915+
and self.parent
916+
and (
917+
isinstance(self.parent, spartan_edge.EdgeHTMLRootContainer)
918+
or not isinstance(self.parent, spartan_edge.EdgeNode)
919+
)
890920
):
891-
clsList.append(edge.EdgeHTMLRoot)
921+
clsList.append(spartan_edge.EdgeHTMLRoot)
892922
elif self.role==controlTypes.ROLE_LIST:
893-
clsList.append(edge.EdgeList)
923+
clsList.append(spartan_edge.EdgeList)
894924
else:
895-
clsList.append(edge.EdgeNode)
896-
elif self.role == controlTypes.ROLE_DOCUMENT and UIAAutomationId == "Microsoft.Windows.PDF.DocumentView":
925+
clsList.append(spartan_edge.EdgeNode)
926+
elif self.windowClassName == "Chrome_RenderWidgetHostHWND":
927+
from . import chromium
928+
from . import web
929+
if (
930+
self.UIATextPattern
931+
and self.role == controlTypes.ROLE_DOCUMENT
932+
and self.parent
933+
and self.parent.role == controlTypes.ROLE_PANE
934+
):
935+
clsList.append(chromium.ChromiumUIADocument)
936+
else:
937+
if self.role == controlTypes.ROLE_LIST:
938+
clsList.append(web.List)
939+
clsList.append(chromium.ChromiumUIA)
940+
elif (
941+
self.role == controlTypes.ROLE_DOCUMENT
942+
and self.UIAElement.cachedAutomationId == "Microsoft.Windows.PDF.DocumentView"
943+
):
897944
# PDFs
898-
from . import edge
899-
clsList.append(edge.EdgeHTMLRoot)
945+
from . import spartan_edge
946+
clsList.append(spartan_edge.EdgeHTMLRoot)
900947
elif (
901948
UIAAutomationId == "RichEditControl"
902949
and "DevExpress.XtraRichEdit" in self.UIAElement.cachedProviderDescription
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# This file is covered by the GNU General Public License.
3+
# See the file COPYING for more details.
4+
# Copyright (C) 2020 NV Access Limited
5+
6+
"""
7+
UIA.anaheim_edge module for specialisations required for Chromium based Edge (code name anaheim).
8+
Note that the UIA.chromium module provides base behaviour for all Chromium based browsers, whereas this
9+
(anaheim_edge) module is only concerned with the window chrome / widgets that are specific to the browser.
10+
11+
This file is currently a placeholder, this line can be deleted when this file is populated. Normally blank
12+
files would not be included in NVDA's repository, however in this case it has been in order to head off any
13+
confusion between the two very different implementations of Edge.
14+
"""

source/NVDAObjects/UIA/chromium.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# This file is covered by the GNU General Public License.
3+
# See the file COPYING for more details.
4+
# Copyright (C) 2020 NV Access limited, Leonard de Ruijter
5+
6+
import UIAHandler
7+
from . import web
8+
import controlTypes
9+
10+
"""
11+
This module provides UIA behaviour specific to the chromium family of browsers.
12+
Note this is more specialised than UIA.web but less so than browser specific modules such as UIA.spartan_edge
13+
or UIA.anaheim_edge.
14+
"""
15+
16+
17+
class ChromiumUIATextInfo(web.UIAWebTextInfo):
18+
19+
def _getFormatFieldAtRange(self, textRange, formatConfig, ignoreMixedValues=False):
20+
formatField = super()._getFormatFieldAtRange(textRange, formatConfig, ignoreMixedValues=ignoreMixedValues)
21+
# Headings are also exposed in the element tree,
22+
# And therefore exposing in a formatField is redundant and causes duplicate reporting.
23+
# So remove heading-level from the formatField if it exists.
24+
try:
25+
del formatField.field['heading-level']
26+
except KeyError:
27+
pass
28+
return formatField
29+
30+
def _getControlFieldForObject(self, obj, isEmbedded=False, startOfNode=False, endOfNode=False):
31+
field = super()._getControlFieldForObject(
32+
obj,
33+
isEmbedded=isEmbedded,
34+
startOfNode=startOfNode,
35+
endOfNode=endOfNode
36+
)
37+
# use the value of comboboxes as content.
38+
if obj.role == controlTypes.ROLE_COMBOBOX:
39+
field['content'] = obj.value
40+
# Layout tables do not have the UIA table pattern
41+
if field['role'] == controlTypes.ROLE_TABLE:
42+
if not obj._getUIACacheablePropertyValue(UIAHandler.UIA_IsTablePatternAvailablePropertyId):
43+
field['table-layout'] = True
44+
# Currently no way to tell if author has explicitly set name.
45+
# Therefore always report the name if the control is not of a type that
46+
# by definition uses its name for content.
47+
# this may cause some duplicate speaking,
48+
# But that is currently better than nothing at all.
49+
if not field.get('nameIsContent') and field.get('name'):
50+
field['alwaysReportName'] = True
51+
return field
52+
53+
54+
class ChromiumUIA(web.UIAWeb):
55+
_TextInfo = ChromiumUIATextInfo
56+
57+
58+
class ChromiumUIATreeInterceptor(web.UIAWebTreeInterceptor):
59+
60+
def _get_documentConstantIdentifier(self):
61+
return self.rootNVDAObject.parent._getUIACacheablePropertyValue(UIAHandler.UIA_AutomationIdPropertyId)
62+
63+
64+
class ChromiumUIADocument(ChromiumUIA):
65+
treeInterceptorClass = ChromiumUIATreeInterceptor
66+
67+
def _get_shouldCreateTreeInterceptor(self):
68+
return self.role == controlTypes.ROLE_DOCUMENT

0 commit comments

Comments
 (0)