From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 885e520bfd3..10d91d04d81 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -2092,12 +2092,14 @@ static void test_UiaProviderFromIAccessible(void) CHECK_CALLED(Accessible2_get_accName); todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity); todo_wine CHECK_CALLED(Accessible2_get_accParent); + IRawElementProviderSimple_Release(elprov2);
elprov2 = (void *)0xdeadbeef; acc_client = NULL; hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2); + IRawElementProviderSimple_Release(elprov2);
IRawElementProviderSimple_Release(elprov); ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 155 ++++++++++----------- dlls/uiautomationcore/uia_provider.c | 108 +++++++++++++- 2 files changed, 181 insertions(+), 82 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 10d91d04d81..da19d3668fa 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1134,37 +1134,36 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_child_accNavigate); SET_EXPECT(Accessible_child_get_accParent); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_FirstChild, &elfrag2); - todo_wine ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref); - todo_wine ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); + ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref); + ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag2, "elfrag2 == NULL\n"); + CHECK_CALLED_MULTI(Accessible_get_accChildCount, 3); + CHECK_CALLED_MULTI(Accessible_get_accChild, 2); + CHECK_CALLED(Accessible_child_get_accState); + CHECK_CALLED(Accessible_child_accNavigate); + CHECK_CALLED(Accessible_child_get_accParent); + + check_fragment_acc(elfrag2, &Accessible_child.IAccessible_iface, CHILDID_SELF); + SET_EXPECT(Accessible_get_accChildCount); + SET_EXPECT(Accessible_get_accChild); + SET_EXPECT(Accessible_get_accState); + hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_NextSibling, &elfrag3); + todo_wine ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag2, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 3); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 2); - todo_wine CHECK_CALLED(Accessible_child_get_accState); - todo_wine CHECK_CALLED(Accessible_child_accNavigate); - todo_wine CHECK_CALLED(Accessible_child_get_accParent); - if (elfrag2) + todo_wine ok(!!elfrag3, "elfrag2 == NULL\n"); + todo_wine CHECK_CALLED(Accessible_get_accChildCount); + todo_wine CHECK_CALLED(Accessible_get_accChild); + todo_wine CHECK_CALLED(Accessible_get_accState); + if (elfrag3) { - check_fragment_acc(elfrag2, &Accessible_child.IAccessible_iface, CHILDID_SELF); - - SET_EXPECT(Accessible_get_accChildCount); - SET_EXPECT(Accessible_get_accChild); - SET_EXPECT(Accessible_get_accState); - hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_NextSibling, &elfrag3); - ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!!elfrag3, "elfrag2 == NULL\n"); - CHECK_CALLED(Accessible_get_accChildCount); - CHECK_CALLED(Accessible_get_accChild); - CHECK_CALLED(Accessible_get_accState); check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3); - IRawElementProviderFragment_Release(elfrag3); ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); - IRawElementProviderFragment_Release(elfrag2); - ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref); - ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); } + IRawElementProviderFragment_Release(elfrag2); + ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
/* Retrieve childid 3 as first child now that Accessible_child is invisible. */ set_accessible_props(&Accessible_child, 0, STATE_SYSTEM_INVISIBLE, 0, NULL, 0, 0, 0, 0); @@ -1173,19 +1172,16 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT_MULTI(Accessible_get_accState, 2); SET_EXPECT(Accessible_child_get_accState); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_FirstChild, &elfrag2); - todo_wine ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag2, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 4); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 3); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accState, 2); - todo_wine CHECK_CALLED(Accessible_child_get_accState); - if (elfrag2) - { - check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, 3); - IRawElementProviderFragment_Release(elfrag2); - ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - } + ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag2, "elfrag2 == NULL\n"); + CHECK_CALLED_MULTI(Accessible_get_accChildCount, 4); + CHECK_CALLED_MULTI(Accessible_get_accChild, 3); + CHECK_CALLED_MULTI(Accessible_get_accState, 2); + CHECK_CALLED(Accessible_child_get_accState); + check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, 3); + IRawElementProviderFragment_Release(elfrag2); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
/* Retrieve childid 4 (Accessible_child2) as last child. */ set_accessible_props(&Accessible_child2, 0, STATE_SYSTEM_FOCUSABLE, 0, NULL, 0, 0, 0, 0); @@ -1195,38 +1191,38 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_child2_accNavigate); SET_EXPECT(Accessible_child2_get_accParent); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_LastChild, &elfrag2); - todo_wine ok(Accessible_child2.ref == 2, "Unexpected refcnt %ld\n", Accessible_child2.ref); - todo_wine ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); + ok(Accessible_child2.ref == 2, "Unexpected refcnt %ld\n", Accessible_child2.ref); + ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag2, "elfrag2 == NULL\n"); + CHECK_CALLED_MULTI(Accessible_get_accChildCount, 2); + CHECK_CALLED(Accessible_get_accChild); + CHECK_CALLED(Accessible_child2_get_accState); + CHECK_CALLED(Accessible_child2_accNavigate); + CHECK_CALLED(Accessible_child2_get_accParent); + + check_fragment_acc(elfrag2, &Accessible_child2.IAccessible_iface, CHILDID_SELF); + SET_EXPECT(Accessible_get_accChildCount); + SET_EXPECT(Accessible_get_accChild); + SET_EXPECT(Accessible_get_accState); + hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_PreviousSibling, &elfrag3); + todo_wine ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag2, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 2); + todo_wine ok(!!elfrag3, "elfrag2 == NULL\n"); + todo_wine CHECK_CALLED(Accessible_get_accChildCount); todo_wine CHECK_CALLED(Accessible_get_accChild); - todo_wine CHECK_CALLED(Accessible_child2_get_accState); - todo_wine CHECK_CALLED(Accessible_child2_accNavigate); - todo_wine CHECK_CALLED(Accessible_child2_get_accParent); - if (elfrag2) + todo_wine CHECK_CALLED(Accessible_get_accState); + if (elfrag3) { - check_fragment_acc(elfrag2, &Accessible_child2.IAccessible_iface, CHILDID_SELF); - - SET_EXPECT(Accessible_get_accChildCount); - SET_EXPECT(Accessible_get_accChild); - SET_EXPECT(Accessible_get_accState); - hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_PreviousSibling, &elfrag3); - ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!!elfrag3, "elfrag2 == NULL\n"); - CHECK_CALLED(Accessible_get_accChildCount); - CHECK_CALLED(Accessible_get_accChild); - CHECK_CALLED(Accessible_get_accState); check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3); - IRawElementProviderFragment_Release(elfrag3); ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); - IRawElementProviderFragment_Release(elfrag2); - ok(Accessible_child2.ref == 1, "Unexpected refcnt %ld\n", Accessible_child2.ref); - ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); }
+ IRawElementProviderFragment_Release(elfrag2); + ok(Accessible_child2.ref == 1, "Unexpected refcnt %ld\n", Accessible_child2.ref); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + /* Retrieve childid 3 as last child, now that Accessible_child2 is STATE_SYSTEM_INVISIBLE. */ set_accessible_props(&Accessible_child2, 0, STATE_SYSTEM_INVISIBLE, 0, NULL, 0, 0, 0, 0); SET_EXPECT_MULTI(Accessible_get_accChildCount, 3); @@ -1234,19 +1230,16 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_get_accState); SET_EXPECT(Accessible_child2_get_accState); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_LastChild, &elfrag2); - todo_wine ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag2, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 3); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 2); - todo_wine CHECK_CALLED(Accessible_get_accState); - todo_wine CHECK_CALLED(Accessible_child2_get_accState); - if (elfrag2) - { - check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, 3); - IRawElementProviderFragment_Release(elfrag2); - ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - } + ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag2, "elfrag2 == NULL\n"); + CHECK_CALLED_MULTI(Accessible_get_accChildCount, 3); + CHECK_CALLED_MULTI(Accessible_get_accChild, 2); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_child2_get_accState); + check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, 3); + IRawElementProviderFragment_Release(elfrag2); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
IRawElementProviderFragment_Release(elfrag); IRawElementProviderSimple_Release(elprov); @@ -1309,15 +1302,15 @@ static void test_uia_prov_from_acc_navigation(void) /* ChildCount of 0, do nothing for First/Last child.*/ SET_EXPECT(Accessible_child_get_accChildCount); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_FirstChild, &elfrag2); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n"); - todo_wine CHECK_CALLED(Accessible_child_get_accChildCount); + CHECK_CALLED(Accessible_child_get_accChildCount);
SET_EXPECT(Accessible_child_get_accChildCount); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_LastChild, &elfrag2); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n"); - todo_wine CHECK_CALLED(Accessible_child_get_accChildCount); + CHECK_CALLED(Accessible_child_get_accChildCount);
/* * In the case of sibling navigation on an IAccessible that wasn't @@ -1438,12 +1431,12 @@ static void test_uia_prov_from_acc_navigation(void) */ hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_FirstChild, &elfrag2); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n");
hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_LastChild, &elfrag2); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n");
/* diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 1dfe447331e..891cb486161 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -220,6 +220,72 @@ static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent) return hr; }
+#define DIR_FORWARD 0 +#define DIR_REVERSE 1 +static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG direction, + IAccessible **child, LONG *child_id, LONG *end_pos) +{ + LONG child_count, cur_pos; + IDispatch *disp; + VARIANT cid; + HRESULT hr; + + *child = NULL; + *child_id = 0; + cur_pos = start_pos; + while (1) + { + hr = IAccessible_get_accChildCount(acc, &child_count); + if (FAILED(hr) || (cur_pos > child_count)) + break; + + variant_init_i4(&cid, cur_pos); + hr = IAccessible_get_accChild(acc, cid, &disp); + if (FAILED(hr)) + break; + + if (hr == S_FALSE) + { + if (!msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE)) + { + *child = acc; + *child_id = *end_pos = cur_pos; + return S_OK; + } + } + else + { + IAccessible *acc_child = NULL; + + hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)&acc_child); + IDispatch_Release(disp); + if (FAILED(hr)) + break; + + variant_init_i4(&cid, CHILDID_SELF); + if (!msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE)) + { + *child = acc_child; + *child_id = CHILDID_SELF; + *end_pos = cur_pos; + return S_OK; + } + + IAccessible_Release(acc_child); + } + + if (direction == DIR_FORWARD) + cur_pos++; + else + cur_pos--; + + if ((cur_pos > child_count) || (cur_pos <= 0)) + break; + } + + return hr; +} + static LONG msaa_role_to_uia_control_type(LONG role) { switch (role) @@ -315,6 +381,9 @@ struct msaa_provider {
BOOL root_acc_check_ran; BOOL is_root_acc; + + IAccessible *parent; + INT child_pos; };
static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov) @@ -326,7 +395,7 @@ static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov) return msaa_prov->is_root_acc;
msaa_prov->root_acc_check_ran = TRUE; - if (V_I4(&msaa_prov->cid) != CHILDID_SELF) + if (V_I4(&msaa_prov->cid) != CHILDID_SELF || msaa_prov->parent) return FALSE;
hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc); @@ -383,6 +452,8 @@ ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface) if (!refcount) { IAccessible_Release(msaa_prov->acc); + if (msaa_prov->parent) + IAccessible_Release(msaa_prov->parent); heap_free(msaa_prov); }
@@ -531,6 +602,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, enum NavigateDirection direction, IRawElementProviderFragment **ret_val) { struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface); + LONG child_count, child_id, end_pos; IRawElementProviderSimple *elprov; IAccessible *acc; HRESULT hr; @@ -567,6 +639,40 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
case NavigateDirection_FirstChild: case NavigateDirection_LastChild: + if (V_I4(&msaa_prov->cid) != CHILDID_SELF) + break; + + hr = IAccessible_get_accChildCount(msaa_prov->acc, &child_count); + if (FAILED(hr) || !child_count) + break; + + if (direction == NavigateDirection_FirstChild) + hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id, &end_pos); + else + hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id, &end_pos); + + if (FAILED(hr) || !acc) + break; + + hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov); + if (SUCCEEDED(hr)) + { + struct msaa_provider *prov = impl_from_msaa_provider(elprov); + + *ret_val = &prov->IRawElementProviderFragment_iface; + prov->parent = msaa_prov->acc; + IAccessible_AddRef(msaa_prov->acc); + if (acc != msaa_prov->acc) + prov->child_pos = end_pos; + else + prov->child_pos = child_id; + } + + if (acc != msaa_prov->acc) + IAccessible_Release(acc); + + break; + case NavigateDirection_NextSibling: case NavigateDirection_PreviousSibling: FIXME("Unimplemented NavigateDirection %d\n", direction);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116889
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1134 error: patch failed: dlls/uiautomationcore/uia_provider.c:220 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1134 error: patch failed: dlls/uiautomationcore/uia_provider.c:220 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1134 error: patch failed: dlls/uiautomationcore/uia_provider.c:220 Task: Patch failed to apply
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 132 +++++++++---------- dlls/uiautomationcore/uia_provider.c | 140 +++++++++++++++++++-- 2 files changed, 195 insertions(+), 77 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index da19d3668fa..15d7b4e784b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1112,13 +1112,13 @@ static void test_uia_prov_from_acc_navigation(void) elfrag2 = (void *)0xdeadbeef; hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n");
elfrag2 = (void *)0xdeadbeef; hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_PreviousSibling, &elfrag2); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n");
/* @@ -1149,18 +1149,16 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_get_accChild); SET_EXPECT(Accessible_get_accState); hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_NextSibling, &elfrag3); - todo_wine ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag3, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED(Accessible_get_accChildCount); - todo_wine CHECK_CALLED(Accessible_get_accChild); - todo_wine CHECK_CALLED(Accessible_get_accState); - if (elfrag3) - { - check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3); - IRawElementProviderFragment_Release(elfrag3); - ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); - } + ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag3, "elfrag2 == NULL\n"); + CHECK_CALLED(Accessible_get_accChildCount); + CHECK_CALLED(Accessible_get_accChild); + CHECK_CALLED(Accessible_get_accState); + check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3); + + IRawElementProviderFragment_Release(elfrag3); + ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); IRawElementProviderFragment_Release(elfrag2); ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); @@ -1206,19 +1204,16 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_get_accChild); SET_EXPECT(Accessible_get_accState); hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_PreviousSibling, &elfrag3); - todo_wine ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag3, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED(Accessible_get_accChildCount); - todo_wine CHECK_CALLED(Accessible_get_accChild); - todo_wine CHECK_CALLED(Accessible_get_accState); - if (elfrag3) - { - check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3); - IRawElementProviderFragment_Release(elfrag3); - ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); - } + ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag3, "elfrag2 == NULL\n"); + CHECK_CALLED(Accessible_get_accChildCount); + CHECK_CALLED(Accessible_get_accChild); + CHECK_CALLED(Accessible_get_accState); + check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3);
+ IRawElementProviderFragment_Release(elfrag3); + ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); IRawElementProviderFragment_Release(elfrag2); ok(Accessible_child2.ref == 1, "Unexpected refcnt %ld\n", Accessible_child2.ref); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); @@ -1338,21 +1333,21 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_child2_accLocation); SET_EXPECT(Accessible_child2_get_accName); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n"); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 5); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 4); - todo_wine CHECK_CALLED(Accessible_child_get_accParent); - todo_wine CHECK_CALLED(Accessible_child_get_accRole); - todo_wine CHECK_CALLED(Accessible_child_get_accState); - todo_wine CHECK_CALLED(Accessible_child_get_accChildCount); - todo_wine CHECK_CALLED(Accessible_child_accLocation); - todo_wine CHECK_CALLED(Accessible_child_get_accName); - todo_wine CHECK_CALLED(Accessible_child2_get_accRole); - todo_wine CHECK_CALLED(Accessible_child2_get_accState); - todo_wine CHECK_CALLED(Accessible_child2_get_accChildCount); - todo_wine CHECK_CALLED(Accessible_child2_accLocation); - todo_wine CHECK_CALLED(Accessible_child2_get_accName); + CHECK_CALLED_MULTI(Accessible_get_accChildCount, 5); + CHECK_CALLED_MULTI(Accessible_get_accChild, 4); + CHECK_CALLED(Accessible_child_get_accParent); + CHECK_CALLED(Accessible_child_get_accRole); + CHECK_CALLED(Accessible_child_get_accState); + CHECK_CALLED(Accessible_child_get_accChildCount); + CHECK_CALLED(Accessible_child_accLocation); + CHECK_CALLED(Accessible_child_get_accName); + CHECK_CALLED(Accessible_child2_get_accRole); + CHECK_CALLED(Accessible_child2_get_accState); + CHECK_CALLED(Accessible_child2_get_accChildCount); + CHECK_CALLED(Accessible_child2_accLocation); + CHECK_CALLED(Accessible_child2_get_accName);
/* Now they have a role mismatch, we can determine our position. */ set_accessible_props(&Accessible_child2, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, @@ -1369,27 +1364,27 @@ static void test_uia_prov_from_acc_navigation(void) * Even though we didn't get a new fragment, now that we know our * position, a reference is added to the parent IAccessible. */ - todo_wine ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elfrag2, "elfrag2 != NULL\n"); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 6); - todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 5); - todo_wine CHECK_CALLED(Accessible_get_accState); - todo_wine CHECK_CALLED(Accessible_child_get_accParent); - todo_wine CHECK_CALLED(Accessible_child_get_accRole); - todo_wine CHECK_CALLED(Accessible_child2_get_accRole); + CHECK_CALLED_MULTI(Accessible_get_accChildCount, 6); + CHECK_CALLED_MULTI(Accessible_get_accChild, 5); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_child_get_accParent); + CHECK_CALLED(Accessible_child_get_accRole); + CHECK_CALLED(Accessible_child2_get_accRole);
/* Now that we know our position, no extra nav work. */ SET_EXPECT(Accessible_get_accChildCount); SET_EXPECT(Accessible_get_accChild); SET_EXPECT(Accessible_get_accState); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2); - todo_wine ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag2, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED(Accessible_get_accChildCount); - todo_wine CHECK_CALLED(Accessible_get_accChild); - todo_wine CHECK_CALLED(Accessible_get_accState); + ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag2, "elfrag2 == NULL\n"); + CHECK_CALLED(Accessible_get_accChildCount); + CHECK_CALLED(Accessible_get_accChild); + CHECK_CALLED(Accessible_get_accState); if (elfrag2) { check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, 3); @@ -1449,23 +1444,20 @@ static void test_uia_prov_from_acc_navigation(void) SET_EXPECT(Accessible_child_accNavigate); SET_EXPECT(Accessible_child_get_accParent); hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2); - todo_wine ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref); - todo_wine ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!elfrag2, "elfrag2 == NULL\n"); - todo_wine CHECK_CALLED(Accessible_get_accChildCount); - todo_wine CHECK_CALLED(Accessible_get_accChild); - todo_wine CHECK_CALLED(Accessible_child_get_accState); - todo_wine CHECK_CALLED(Accessible_child_accNavigate); - todo_wine CHECK_CALLED(Accessible_child_get_accParent); - if (elfrag2) - { - check_fragment_acc(elfrag2, &Accessible_child.IAccessible_iface, CHILDID_SELF); - IRawElementProviderFragment_Release(elfrag2); - ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref); - ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); - } + ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref); + ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag2, "elfrag2 == NULL\n"); + CHECK_CALLED(Accessible_get_accChildCount); + CHECK_CALLED(Accessible_get_accChild); + CHECK_CALLED(Accessible_child_get_accState); + CHECK_CALLED(Accessible_child_accNavigate); + CHECK_CALLED(Accessible_child_get_accParent); + check_fragment_acc(elfrag2, &Accessible_child.IAccessible_iface, CHILDID_SELF);
+ IRawElementProviderFragment_Release(elfrag2); + ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref); + ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref); IRawElementProviderFragment_Release(elfrag); 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 891cb486161..f72628885bd 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -223,7 +223,7 @@ static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent) #define DIR_FORWARD 0 #define DIR_REVERSE 1 static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG direction, - IAccessible **child, LONG *child_id, LONG *end_pos) + IAccessible **child, LONG *child_id, LONG *end_pos, BOOL check_visible) { LONG child_count, cur_pos; IDispatch *disp; @@ -246,7 +246,7 @@ static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG di
if (hr == S_FALSE) { - if (!msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE)) + if (!check_visible || !msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE)) { *child = acc; *child_id = *end_pos = cur_pos; @@ -263,7 +263,7 @@ static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG di break;
variant_init_i4(&cid, CHILDID_SELF); - if (!msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE)) + if (!check_visible || !msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE)) { *child = acc_child; *child_id = CHILDID_SELF; @@ -286,6 +286,83 @@ static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG di return hr; }
+static HRESULT msaa_acc_get_child_pos(IAccessible *acc, IAccessible **out_parent, LONG *out_pos) +{ + IAccessible *child, *parent, *match, **children; + LONG child_count, child_id, end_pos, match_pos; + HRESULT hr; + int i; + + *out_parent = NULL; + *out_pos = 0; + hr = msaa_acc_get_parent(acc, &parent); + if (FAILED(hr) || !parent) + return hr; + + hr = IAccessible_get_accChildCount(parent, &child_count); + if (FAILED(hr) || !child_count) + { + IAccessible_Release(parent); + return hr; + } + + children = heap_alloc_zero(sizeof(*children) * child_count); + if (!children) + return E_OUTOFMEMORY; + + match = NULL; + for (i = 0; i < child_count; i++) + { + hr = msaa_acc_get_next_child(parent, i + 1, DIR_FORWARD, &child, &child_id, &end_pos, FALSE); + if (FAILED(hr) || !child) + goto exit; + + if (child != parent) + children[i] = child; + } + + for (i = 0; i < child_count; i++) + { + if (!children[i]) + continue; + + if (msaa_acc_compare(acc, children[i])) + { + if (!match) + { + match = children[i]; + match_pos = i + 1; + } + /* Can't have more than one IAccessible match. */ + else + { + match = NULL; + match_pos = 0; + break; + } + } + } + +exit: + if (match) + { + *out_parent = parent; + *out_pos = match_pos; + } + else + IAccessible_Release(parent); + + for (i = 0; i < child_count; i++) + { + if (children[i]) + IAccessible_Release(children[i]); + } + + heap_free(children); + + return hr; +} + static LONG msaa_role_to_uia_control_type(LONG role) { switch (role) @@ -647,9 +724,11 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, break;
if (direction == NavigateDirection_FirstChild) - hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id, &end_pos); + hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id, + &end_pos, TRUE); else - hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id, &end_pos); + hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id, + &end_pos, TRUE);
if (FAILED(hr) || !acc) break; @@ -675,8 +754,55 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
case NavigateDirection_NextSibling: case NavigateDirection_PreviousSibling: - FIXME("Unimplemented NavigateDirection %d\n", direction); - return E_NOTIMPL; + if (msaa_check_root_acc(msaa_prov)) + break; + + if (!msaa_prov->parent) + { + if (V_I4(&msaa_prov->cid) != CHILDID_SELF) + { + msaa_prov->parent = msaa_prov->acc; + IAccessible_AddRef(msaa_prov->acc); + msaa_prov->child_pos = V_I4(&msaa_prov->cid); + } + else + { + hr = msaa_acc_get_child_pos(msaa_prov->acc, &acc, &child_id); + if (FAILED(hr) || !acc) + break; + msaa_prov->parent = acc; + msaa_prov->child_pos = child_id; + } + } + + if (direction == NavigateDirection_NextSibling) + hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos + 1, DIR_FORWARD, + &acc, &child_id, &end_pos, TRUE); + else + hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos - 1, DIR_REVERSE, + &acc, &child_id, &end_pos, TRUE); + + if (FAILED(hr) || !acc) + break; + + hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov); + if (SUCCEEDED(hr)) + { + struct msaa_provider *prov = impl_from_msaa_provider(elprov); + + *ret_val = &prov->IRawElementProviderFragment_iface; + prov->parent = msaa_prov->parent; + IAccessible_AddRef(msaa_prov->parent); + if (acc != msaa_prov->acc) + prov->child_pos = end_pos; + else + prov->child_pos = child_id; + } + + if (acc != msaa_prov->parent) + IAccessible_Release(acc); + + break;
default: FIXME("Invalid NavigateDirection %d\n", direction);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116890
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1134 error: patch failed: dlls/uiautomationcore/uia_provider.c:220 error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1112 error: patch failed: dlls/uiautomationcore/uia_provider.c:223 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1134 error: patch failed: dlls/uiautomationcore/uia_provider.c:220 error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1112 error: patch failed: dlls/uiautomationcore/uia_provider.c:223 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1134 error: patch failed: dlls/uiautomationcore/uia_provider.c:220 error: patch failed: dlls/uiautomationcore/tests/uiautomation.c:1112 error: patch failed: dlls/uiautomationcore/uia_provider.c:223 Task: Patch failed to apply
This merge request was closed by Connor McAdams.