From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 83 ++++++++++++++++++++++ dlls/uiautomationcore/uia_provider.c | 39 ++++++++++ 2 files changed, 122 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index ce3ee303fd1..2971f356688 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -3383,6 +3383,7 @@ static void test_uia_prov_from_acc_navigation(void) static void test_uia_prov_from_acc_properties(void) { IRawElementProviderSimple *elprov; + RECT rect[2] = { 0 }; HRESULT hr; VARIANT v; int i, x; @@ -3476,6 +3477,88 @@ static void test_uia_prov_from_acc_properties(void) } Accessible.state = 0;
+ /* + * UIA_IsOffscreenPropertyId relies upon either STATE_SYSTEM_OFFSCREEN + * being set, or accLocation returning a location that is within the + * client area bounding box of the HWND it is contained within. + */ + set_accessible_props(&Accessible, 0, STATE_SYSTEM_OFFSCREEN, 0, L"Accessible", 0, 0, 0, 0); + SET_EXPECT(Accessible_get_accState); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsOffscreenPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "V_VT(&v) = %d\n", V_VT(&v)); + ok(check_variant_bool(&v, TRUE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + CHECK_CALLED(Accessible_get_accState); + + /* accLocation fails, will return FALSE. */ + set_accessible_props(&Accessible, 0, ~STATE_SYSTEM_OFFSCREEN, 0, L"Accessible", 0, 0, 0, 0); + SET_EXPECT(Accessible_get_accState); + SET_EXPECT(Accessible_accLocation); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsOffscreenPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "V_VT(&v) = %d\n", V_VT(&v)); + ok(check_variant_bool(&v, FALSE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_accLocation); + + /* Window is visible, Accessible is within its bounds. */ + ShowWindow(Accessible.ow_hwnd, SW_SHOW); + ok(GetClientRect(Accessible.ow_hwnd, &rect[0]), "GetClientRect returned FALSE\n"); + MapWindowPoints(Accessible.ow_hwnd, NULL, (POINT *)&rect[0], 2); + + set_accessible_props(&Accessible, 0, ~STATE_SYSTEM_OFFSCREEN, 0, L"Accessible", rect[0].left, rect[0].top, + (rect[0].right - rect[0].left), (rect[0].bottom - rect[0].top)); + SET_EXPECT(Accessible_get_accState); + SET_EXPECT(Accessible_accLocation); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsOffscreenPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "Unexpected VT %d\n", V_VT(&v)); + ok(check_variant_bool(&v, FALSE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_accLocation); + + /* + * Window is invisible, Accessible is within its bounds. Window visibility + * doesn't effect whether or not an IAccessible is considered offscreen. + */ + ShowWindow(Accessible.ow_hwnd, SW_HIDE); + set_accessible_props(&Accessible, 0, ~STATE_SYSTEM_OFFSCREEN, 0, L"Accessible", rect[0].left, rect[0].top, + (rect[0].right - rect[0].left), (rect[0].bottom - rect[0].top)); + SET_EXPECT(Accessible_get_accState); + SET_EXPECT(Accessible_accLocation); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsOffscreenPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "Unexpected VT %d\n", V_VT(&v)); + ok(check_variant_bool(&v, FALSE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_accLocation); + + /* Accessible now outside of its window's bounds. */ + set_accessible_props(&Accessible, 0, ~STATE_SYSTEM_OFFSCREEN, 0, L"Accessible", rect[0].right, rect[0].bottom, + 10, 10); + SET_EXPECT(Accessible_get_accState); + SET_EXPECT(Accessible_accLocation); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsOffscreenPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "V_VT(&v) = %d\n", V_VT(&v)); + ok(check_variant_bool(&v, TRUE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_accLocation); + + /* Accessible within window bounds, but not client area bounds. */ + ok(GetWindowRect(Accessible.ow_hwnd, &rect[1]), "GetClientRect returned FALSE\n"); + set_accessible_props(&Accessible, 0, ~STATE_SYSTEM_OFFSCREEN, 0, L"Accessible", rect[1].left, rect[1].top, + rect[0].left - 1, rect[0].top - 1); + + SET_EXPECT(Accessible_get_accState); + SET_EXPECT(Accessible_accLocation); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsOffscreenPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "V_VT(&v) = %d\n", V_VT(&v)); + ok(check_variant_bool(&v, TRUE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_accLocation); + IRawElementProviderSimple_Release(elprov); ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index a7d41248abc..119a7e69abc 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -676,6 +676,45 @@ HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface, break; }
+ case UIA_IsOffscreenPropertyId: + { + RECT rect[2] = { 0 }; + RECT intersect_rect; + LONG width, height; + + variant_init_bool(ret_val, FALSE); + if (msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_OFFSCREEN)) + { + variant_init_bool(ret_val, TRUE); + break; + } + + hr = IAccessible_accLocation(msaa_prov->acc, &rect[0].left, &rect[0].top, &width, &height, msaa_prov->cid); + if (FAILED(hr)) + break; + + rect[0].right = rect[0].left + width; + rect[0].bottom = rect[0].top + height; + SetLastError(NOERROR); + if (!GetClientRect(msaa_prov->hwnd, &rect[1])) + { + if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + variant_init_bool(ret_val, TRUE); + break; + } + + SetLastError(NOERROR); + if (!MapWindowPoints(msaa_prov->hwnd, NULL, (POINT *)&rect[1], 2) && GetLastError()) + { + if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + variant_init_bool(ret_val, TRUE); + break; + } + + variant_init_bool(ret_val, !IntersectRect(&intersect_rect, &rect[0], &rect[1])); + break; + } + default: FIXME("Unimplemented propertyId %d\n", prop_id); break;