99 Optional ,
1010)
1111import typing
12- import weakref
1312from ctypes import byref
1413from . import VirtualBuffer , VirtualBufferTextInfo , VBufStorage_findMatch_word , VBufStorage_findMatch_notEmpty
1514import treeInterceptorHandler
@@ -264,87 +263,12 @@ def _get_location(self) -> locationHelper.RectLTWH:
264263class Gecko_ia2 (VirtualBuffer ):
265264
266265 TextInfo = Gecko_ia2_TextInfo
267- #: Maps NVDAObjects to a list of iframes/frames in that object's ancestry,
268- #: ordered from deepest to shallowest. The key is held as a weak reference so
269- #: that the cache for an object is cleaned up when that object dies. Each
270- #: frame/iframe in the lists is a tuple of (IAccessible2_2, uniqueId). This
271- #: cache is used across instances.
272- _framesCache = weakref .WeakKeyDictionary ()
273266 _nativeAppSelectionModeSupported = True
274267
275268 def __init__ (self ,rootNVDAObject ):
276269 super (Gecko_ia2 ,self ).__init__ (rootNVDAObject ,backendName = "gecko_ia2" )
277270 self ._initialScrollObj = None
278271
279- @staticmethod
280- def _getEmbedderFrame (acc ):
281- """Get the iframe/frame (if any) which contains the given object.
282- For example, if acc is a button inside an iframe, this will return the iframe.
283- """
284- try :
285- # 1. Get the containing document.
286- if not isinstance (acc , IA2 .IAccessible2_2 ):
287- # IAccessible NVDAObjects currently fetch IA2, but we need IA2_2 for relationTargetsOfType.
288- # (Out-of-process, for a single relation, this is cheaper than IA2::relations.)
289- acc = acc .QueryInterface (IA2 .IAccessible2_2 )
290- targets , count = acc .relationTargetsOfType (
291- IAccessibleHandler .RelationType .CONTAINING_DOCUMENT ,
292- 1 # max relations to fetch
293- )
294- if count == 0 :
295- return None
296- doc = targets [0 ].QueryInterface (IA2 .IAccessible2_2 )
297- # 2. Get its parent (the embedder); e.g. iframe.
298- embedder = doc .accParent
299- if not embedder :
300- return None
301- embedder = embedder .QueryInterface (IA2 .IAccessible2_2 )
302- # 3. Make sure this is an iframe/frame.
303- attribs = embedder .attributes
304- if "tag:browser;" in attribs :
305- # This is a top level browser, not an iframe/frame.
306- return None
307- return embedder
308- except COMError :
309- return None
310-
311- @classmethod
312- def _iterIdsToTryWithAccChild (cls , obj ):
313- """Return the child ids we should try with accChild in order to determine
314- whether this object is a descendant of a particular document.
315- """
316- # 1. Try the object itself.
317- acc = obj .IAccessibleObject
318- accId = obj .IA2UniqueID
319- yield accId
320- # 2. If this fails, this might be because the object is in an
321- # out-of-process frame, in which case the embedder document won't know
322- # about it. Try embedder frames.
323- # 2.1. Try cached frames. We cache because walking frames is expensive,
324- # and when trying to work out what TreeInterceptor this object belongs to,
325- # we'll need to query these frames for each TreeInterceptor.
326- cache = cls ._framesCache .setdefault (obj , [])
327- for acc , accId in cache :
328- if not acc :
329- # All frames were cached in a previous run. There are no more.
330- return
331- yield accId
332- # 2.2. Walk remaining ancestor embedder frames, filling the cache as we go.
333- while True :
334- acc = cls ._getEmbedderFrame (acc )
335- if not acc :
336- # No more. Signal this in the cache.
337- cache .append ((None , None ))
338- return
339- try :
340- accId = acc .uniqueID
341- except COMError :
342- # Dead object.
343- cache .append ((None , None ))
344- return
345- cache .append ((acc , accId ))
346- yield accId
347-
348272 def __contains__ (self ,obj ):
349273 if (
350274 not (
@@ -355,19 +279,13 @@ def __contains__(self,obj):
355279 or not winUser .isDescendantWindow (self .rootNVDAObject .windowHandle , obj .windowHandle )
356280 ):
357281 return False
358- for accId in self ._iterIdsToTryWithAccChild (obj ):
359- if accId == self .rootID :
360- return True
361- try :
362- self .rootNVDAObject .IAccessibleObject .accChild (accId )
363- # The object is definitely a descendant of the document.
364- break
365- except COMError :
366- pass
367- else :
368- # The object is definitely not a descendant of the document.
282+ accId = obj .IA2UniqueID
283+ if accId == self .rootID :
284+ return True
285+ try :
286+ self .rootNVDAObject .IAccessibleObject .accChild (accId )
287+ except COMError :
369288 return False
370-
371289 return not self ._isNVDAObjectInApplication (obj )
372290
373291 def _get_isAlive (self ):
@@ -393,7 +311,15 @@ def _get_isAlive(self):
393311 return not isDefunct
394312
395313 def getNVDAObjectFromIdentifier (self , docHandle , ID ):
396- return NVDAObjects .IAccessible .getNVDAObjectFromEvent (docHandle , winUser .OBJID_CLIENT , ID )
314+ try :
315+ pacc = self .rootNVDAObject .IAccessibleObject .accChild (ID )
316+ except COMError :
317+ return None
318+ return NVDAObjects .IAccessible .IAccessible (
319+ windowHandle = docHandle ,
320+ IAccessibleObject = IAccessibleHandler .normalizeIAccessible (pacc ),
321+ IAccessibleChildID = 0
322+ )
397323
398324 def getIdentifierFromNVDAObject (self ,obj ):
399325 docHandle = obj .windowHandle
0 commit comments