def _get_boundingRects(self): if self.isCollapsed: return [] startOffset = self._startOffset try: firstVisibleOffset = self._getFirstVisibleOffset() if firstVisibleOffset >= 0: startOffset = max(startOffset, firstVisibleOffset) except (LookupError, NotImplementedError): pass getLocationFromOffset = self._getBoundingRectFromOffset try: startLocation = getLocationFromOffset(startOffset) except NotImplementedError: # Getting bounding rectangles is not implemented. # Therefore, we need to create a bounding rectangle with points. # This, though less accurate, is acceptable for use cases within NVDA. getLocationFromOffset = self._getPointFromOffset startLocation = getLocationFromOffset(startOffset) inclusiveEndOffset = self._endOffset - 1 try: lastVisibleOffset = self._getLastVisibleOffset() if lastVisibleOffset >= startOffset: inclusiveEndOffset = min(inclusiveEndOffset, lastVisibleOffset) except (LookupError, NotImplementedError): pass # If the inclusive end offset is greater than the start offset, we are working with a range. # If not, i.e. the range only contains one character, we have only one location to deal with. objLocation = self.obj.rootNVDAObject.location if isinstance( self.obj, TreeInterceptor) else self.obj.location rects = [] if inclusiveEndOffset > startOffset: offset = startOffset while offset <= inclusiveEndOffset: lineStart, lineEnd = self._getLineOffsets(offset) if lineStart < startOffset: lineStart = startOffset # Line offsets are exclusive, so the end offset is at the start of the next line, if any. inclusiveLineEnd = lineEnd - 1 if inclusiveLineEnd > inclusiveEndOffset: # The end offset is in this line inclusiveLineEnd = inclusiveEndOffset rects.append( RectLTWH.fromCollection( startLocation if lineStart == startOffset else getLocationFromOffset(lineStart), getLocationFromOffset(inclusiveLineEnd))) offset = inclusiveLineEnd + 1 else: if isinstance(startLocation, textInfos.Point): rects.append(RectLTWH.fromPoint(startLocation)) else: rects.append(startLocation) intersectedRects = [] for rect in rects: intersection = rect.intersection(objLocation) if not any(intersection): continue intersectedRects.append(intersection) return intersectedRects
def test_collection(self): """Tests whether a collection of several rectangle and point types convert to the expected L{RectLTRB}.""" rect=RectLTRB(left=10, top=15, right=500, bottom=1000) self.assertEqual(RectLTRB.fromCollection( rect.topLeft, rect.bottomRight, rect.center, Point(15, 15), Point(20, 20), Point(50, 50), Point(400, 400), POINT(x=15, y=15), POINT(x=20, y=20), POINT(x=50, y=50), POINT(x=400, y=400), RectLTRB(left=450, top=450, right=490, bottom=990), RECT(450, 450, 490, 990) ), rect) location=RectLTWH(left=10, top=15, width=500, height=1000) self.assertEqual(RectLTWH.fromCollection( location.topLeft, location.bottomRight, location.center, Point(15, 15), Point(20, 20), Point(50, 50), Point(400, 400), POINT(x=15, y=15), POINT(x=20, y=20), POINT(x=50, y=50), POINT(x=400, y=400), RectLTRB(left=450, top=450, right=505, bottom=1010), RECT(450, 450, 490, 990) ), location)
def test_expandOrShrink(self): """Tests the expand or shrink functionality to resize a rectangle given a specified margin.""" rect = RectLTRB(left=10, top=10, right=20, bottom=20) self.assertEqual(rect.expandOrShrink(10), RectLTRB(left=0, top=0, right=30, bottom=30)) self.assertEqual(rect.expandOrShrink(-2), RectLTRB(left=12, top=12, right=18, bottom=18)) self.assertRaises(RuntimeError, rect.expandOrShrink, -10) location = RectLTWH(left=10, top=10, width=10, height=10) self.assertEqual(location.expandOrShrink(10), RectLTWH(left=0, top=0, width=30, height=30)) self.assertEqual(location.expandOrShrink(-2), RectLTWH(left=12, top=12, width=6, height=6)) self.assertRaises(RuntimeError, location.expandOrShrink, -10)
def _getBoundingRectFromOffset(self, offset): word = None for nextWord in self.result.words: if nextWord.offset > offset: # Stop! We need the word before this. break word = nextWord return RectLTWH(word.left, word.top, word.width, word.height)
def _get_location(self): if not isinstance(self, UIA): return RectLTWH( self._window.Left, self._window.Top, self._window.Width, self._window.Height ) return super().location
def _get_boundingRects(self): # The base implementation for OffsetsTextInfo is conservative, # However here, since bounding rectangles are always known and on screen, we can use them all. lineEndOffsets = [ offset for offset in self._storyFieldsAndRects[2] if self._startOffset < offset < self._endOffset ] lineEndOffsets.append(self._endOffset) startOffset = endOffset = self._startOffset rects = [] for lineEndOffset in lineEndOffsets: startOffset=endOffset endOffset=lineEndOffset rects.append(RectLTWH.fromCollection(*self._storyFieldsAndRects[1][startOffset:endOffset].toPhysical(self.obj.windowHandle))) return rects
def _get_boundingRects(self): # The base implementation for OffsetsTextInfo is conservative, # However here, since bounding rectangles are always known and on screen, we can use them all. lineEndOffsets = [ offset for offset in self._storyFieldsAndRects[2] if self._startOffset < offset < self._endOffset ] lineEndOffsets.append(self._endOffset) startOffset = endOffset = self._startOffset rects = [] for lineEndOffset in lineEndOffsets: startOffset=endOffset endOffset=lineEndOffset rects.append(RectLTWH.fromCollection(*self._storyFieldsAndRects[1][startOffset:endOffset]).toPhysical(self.obj.windowHandle)) return rects
def updateLocationForDisplays(self): if vision._isDebug(): log.debug("Updating NVDAHighlighter window location for displays") displays = [ wx.Display(i).GetGeometry() for i in range(wx.Display.GetCount()) ] screenWidth, screenHeight, minPos = getTotalWidthAndHeightAndMinimumPosition( displays) # Hack: Windows has a "feature" that will stop desktop shortcut hotkeys from working # when a window is full screen. # Removing one line of pixels from the bottom of the screen will fix this. left = minPos.x top = minPos.y width = screenWidth height = screenHeight - 1 self.location = RectLTWH(left, top, width, height) winUser.user32.ShowWindow(self.handle, winUser.SW_HIDE) if not winUser.user32.SetWindowPos(self.handle, winUser.HWND_TOPMOST, left, top, width, height, winUser.SWP_NOACTIVATE): raise WinError() winUser.user32.ShowWindow(self.handle, winUser.SW_SHOWNA)
def _get_boundingRects(self): # The base implementation for OffsetsTextInfo is conservative, # However here, since bounding rectangles are always known and on screen, we can use them all. lineEndOffsets = [ offset for offset in self._storyFieldsAndRects[2] if self._startOffset < offset < self._endOffset ] lineEndOffsets.append(self._endOffset) startOffset = endOffset = self._startOffset rects = [] for lineEndOffset in lineEndOffsets: startOffset = endOffset endOffset = lineEndOffset lineRect = RectLTWH.fromCollection( *self._storyFieldsAndRects[1][startOffset:endOffset]) try: lineRect = lineRect.toPhysical(self.obj.windowHandle) except RuntimeError: raise LookupError( f"Couldn't convert line rectangle at offsets {startOffset} to {endOffset} " "to physical coordinates") rects.append(lineRect) return rects
class TestLinesWordsResult(unittest.TestCase): """Tests that contentRecog.LinesWordsResult and contentRecog.LwrTextInfo correctly parse and process the JSON from a recognizer. """ DATA = [[{ "x": 100, "y": 200, "width": 10, "height": 20, "text": "word1" }, { "x": 110, "y": 200, "width": 10, "height": 20, "text": "word2" }], [{ "x": 100, "y": 220, "width": 10, "height": 20, "text": "word3" }, { "x": 110, "y": 220, "width": 10, "height": 20, "text": "word4" }]] TOP = 0 BOTTOM = 23 WORD1_OFFSETS = (0, 6) WORD1_SECOND = 1 WORD1_LAST = 5 WORD1_RECT = RectLTWH(100, 200, 10, 20) WORD2_START = 6 WORD2_OFFSETS = (6, 12) WORD2_RECT = RectLTWH(110, 200, 10, 20) WORD3_OFFSETS = (12, 18) WORD3_START = 12 WORD3_RECT = RectLTWH(100, 220, 10, 20) WORD4_OFFSETS = (18, 24) WORD4_RECT = RectLTWH(110, 220, 10, 20) LINE1_OFFSETS = (0, 12) LINE1_SECOND = 1 LINE1_LAST = 11 LINE2_OFFSETS = (12, 24) LINE2_START = 12 def setUp(self): info = contentRecog.RecogImageInfo(0, 0, 1000, 2000, 1) self.result = contentRecog.LinesWordsResult(self.DATA, info) self.fakeObj = FakeNVDAObject() self.textInfo = self.result.makeTextInfo(self.fakeObj, textInfos.POSITION_FIRST) def test_text(self): self.assertEqual(self.result.text, "word1 word2\nword3 word4\n") def test_textLen(self): self.assertEqual(self.result.textLen, len(self.result.text)) def test_wordOffsetsAtTop(self): actual = self.textInfo._getWordOffsets(self.TOP) self.assertEqual(actual, self.WORD1_OFFSETS) def test_wordOffsetsAtWord1SecondChar(self): actual = self.textInfo._getWordOffsets(self.WORD1_SECOND) self.assertEqual(actual, self.WORD1_OFFSETS) def test_wordOffsetsAtWord1LastChar(self): actual = self.textInfo._getWordOffsets(self.WORD1_LAST) self.assertEqual(actual, self.WORD1_OFFSETS) def test_wordOffsetsAtWord2Start(self): actual = self.textInfo._getWordOffsets(self.WORD2_START) self.assertEqual(actual, self.WORD2_OFFSETS) def test_wordOffsetsAtLine2Start(self): actual = self.textInfo._getWordOffsets(self.LINE2_START) self.assertEqual(actual, self.WORD3_OFFSETS) def test_wordOffsetsAtBottom(self): actual = self.textInfo._getWordOffsets(self.BOTTOM) self.assertEqual(actual, self.WORD4_OFFSETS) def test_lineOffsetsAtTop(self): actual = self.textInfo._getLineOffsets(self.TOP) self.assertEqual(actual, self.LINE1_OFFSETS) def test_lineOffsetsAtLine1SecondChar(self): actual = self.textInfo._getLineOffsets(self.LINE1_SECOND) self.assertEqual(actual, self.LINE1_OFFSETS) def test_lineOffsetsAtLine1LastChar(self): actual = self.textInfo._getLineOffsets(self.LINE1_LAST) self.assertEqual(actual, self.LINE1_OFFSETS) def test_lineOffsetsAtLine2Start(self): actual = self.textInfo._getLineOffsets(self.LINE2_START) self.assertEqual(actual, self.LINE2_OFFSETS) def test_lineOffsetsAtBottom(self): actual = self.textInfo._getLineOffsets(self.BOTTOM) self.assertEqual(actual, self.LINE2_OFFSETS) def test_boundingRectFromOffsetAtTop(self): actual = self.textInfo._getBoundingRectFromOffset(self.TOP) self.assertEqual(actual, self.WORD1_RECT) def test_boundingRectFromOffsetAtWord1SecondChar(self): actual = self.textInfo._getBoundingRectFromOffset(self.WORD1_SECOND) self.assertEqual(actual, self.WORD1_RECT) def test_boundingRectFromOffsetAtWord1LastChar(self): actual = self.textInfo._getBoundingRectFromOffset(self.WORD1_LAST) self.assertEqual(actual, self.WORD1_RECT) def test_boundingRectFromOffsetAtWord2Start(self): actual = self.textInfo._getBoundingRectFromOffset(self.WORD2_START) self.assertEqual(actual, self.WORD2_RECT) def test_boundingRectFromOffsetAtLine2Start(self): actual = self.textInfo._getBoundingRectFromOffset(self.LINE2_START) self.assertEqual(actual, self.WORD3_RECT) def test_boundingRectFromOffsetAtBottom(self): actual = self.textInfo._getBoundingRectFromOffset(self.BOTTOM) self.assertEqual(actual, self.WORD4_RECT) def test_copyTextInfo(self): copy = self.textInfo.copy() self.assertEqual(copy, self.textInfo)
def _get_location(self): return RectLTWH(self._JABAccContextInfo.x, self._JABAccContextInfo.y, self._JABAccContextInfo.width, self._JABAccContextInfo.height)
def _getBoundingRectFromOffset(self, offset): rect = self.obj.jabContext.getAccessibleTextRect(offset) try: return RectLTWH(rect.x, rect.y, rect.width, rect.height).toLTRB() except ValueError: raise LookupError
def _get_location(self): r = ctypes.wintypes.RECT() ctypes.windll.user32.GetWindowRect(self.windowHandle, ctypes.byref(r)) return RectLTWH.fromCompatibleType(r)
def _get_boundingRects(self): if self.isCollapsed: return [] startOffset = self._startOffset try: firstVisibleOffset = self._getFirstVisibleOffset() if firstVisibleOffset >=0: startOffset = max(startOffset, firstVisibleOffset) except (LookupError, NotImplementedError): pass getLocationFromOffset = self._getBoundingRectFromOffset try: startLocation = getLocationFromOffset(startOffset) except NotImplementedError: # Getting bounding rectangles is not implemented. # Therefore, we need to create a bounding rectangle with points. # This, though less accurate, is acceptable for use cases within NVDA. getLocationFromOffset = self._getPointFromOffset startLocation = getLocationFromOffset(startOffset) inclusiveEndOffset = self._endOffset - 1 try: lastVisibleOffset = self._getLastVisibleOffset() if lastVisibleOffset >= startOffset: inclusiveEndOffset = min(inclusiveEndOffset, lastVisibleOffset) except (LookupError, NotImplementedError): pass # If the inclusive end offset is greater than the start offset, we are working with a range. # If not, i.e. the range only contains one character, we have only one location to deal with. obj = self.obj.rootNVDAObject if isinstance(self.obj, TreeInterceptor) else self.obj for i in range(100): objLocation = obj.location if objLocation: break obj = obj.parent if not objLocation: raise LookupError rects = [] if inclusiveEndOffset > startOffset: offset = startOffset while offset <= inclusiveEndOffset: lineStart, lineEnd = self._getLineOffsets(offset) if lineStart < startOffset: lineStart = startOffset # Line offsets are exclusive, so the end offset is at the start of the next line, if any. inclusiveLineEnd = lineEnd - 1 if inclusiveLineEnd > inclusiveEndOffset: # The end offset is in this line inclusiveLineEnd = inclusiveEndOffset rects.append( RectLTWH.fromCollection( startLocation if lineStart == startOffset else getLocationFromOffset(lineStart), getLocationFromOffset(inclusiveLineEnd) ) ) offset = inclusiveLineEnd + 1 else: if isinstance(startLocation, textInfos.Point): rects.append(RectLTWH.fromPoint(startLocation)) else: rects.append(startLocation) intersectedRects = [] for rect in rects: intersection = rect.intersection(objLocation) if not any(intersection): continue intersectedRects.append(intersection) return intersectedRects
def test_equal(self): self.assertEqual(RectLTRB(left=2, top=2, right=4, bottom=4), RectLTRB(left=2, top=2, right=4, bottom=4)) self.assertNotEqual(RectLTRB(left=2, top=2, right=4, bottom=4), RectLTRB(left=2, top=2, right=6, bottom=6)) self.assertEqual(RectLTRB(left=2, top=2, right=4, bottom=4), RectLTWH(left=2, top=2, width=2, height=2)) self.assertNotEqual(RectLTRB(left=2, top=2, right=4, bottom=4), RectLTWH(left=2, top=2, width=4, height=4))
def _get_location(self): r=ctypes.wintypes.RECT() ctypes.windll.user32.GetWindowRect(self.windowHandle,ctypes.byref(r)) return RectLTWH.fromCompatibleType(r)
def test_fromFloatCollection(self): self.assertEqual(RectLTRB(left=10, top=10, right=20, bottom=20), RectLTRB.fromFloatCollection(10.0, 10.0, 20.0, 20.0)) self.assertEqual(RectLTWH(left=10, top=10, width=20, height=20), RectLTWH.fromFloatCollection(10.0, 10.0, 20.0, 20.0))
def _getColumnLocation(self, column): colHeader = self.parent.getHeader().getChild(column - 1) return RectLTWH(left=colHeader.location.left, top=self.location.top, width=colHeader.location.width, height=self.location.height)