diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index 7c281ab364..c30db2841c 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -2191,20 +2191,63 @@ static HRESULT WINAPI ITextRange_fnMove(ITextRange *me, LONG unit, LONG count, L return E_NOTIMPL; } +static HRESULT textrange_movestart(ITextRange *range, ME_TextEditor *editor, LONG unit, LONG count, LONG *delta) +{ + LONG old_start, old_end, new_start, new_end; + HRESULT hr = S_OK; + + if (!count) + { + if (delta) + *delta = 0; + return S_FALSE; + } + + ITextRange_GetStart(range, &old_start); + ITextRange_GetEnd(range, &old_end); + switch (unit) + { + case tomCharacter: + { + ME_Cursor cursor; + LONG moved; + + ME_CursorFromCharOfs(editor, old_start, &cursor); + moved = ME_MoveCursorChars(editor, &cursor, count, FALSE); + new_start = old_start + moved; + new_end = old_end; + if (new_end < new_start) + new_end = new_start; + if (delta) + *delta = moved; + break; + } + default: + FIXME("unit %d is not supported\n", unit); + return E_NOTIMPL; + } + if (new_start == old_start) + hr = S_FALSE; + ITextRange_SetStart(range, new_start); + ITextRange_SetEnd(range, new_end); + + return hr; +} + static HRESULT WINAPI ITextRange_fnMoveStart(ITextRange *me, LONG unit, LONG count, LONG *delta) { ITextRangeImpl *This = impl_from_ITextRange(me); - FIXME("(%p)->(%d %d %p): stub\n", This, unit, count, delta); + TRACE("(%p)->(%d %d %p)\n", This, unit, count, delta); if (!This->child.reole) return CO_E_RELEASED; - return E_NOTIMPL; + return textrange_movestart(me, This->child.reole->editor, unit, count, delta); } -static HRESULT textrange_moveend(ITextRange *range, LONG unit, LONG count, LONG *delta) +static HRESULT textrange_moveend(ITextRange *range, ME_TextEditor *editor, LONG unit, LONG count, LONG *delta) { LONG old_start, old_end, new_start, new_end; HRESULT hr = S_OK; @@ -2220,6 +2263,21 @@ static HRESULT textrange_moveend(ITextRange *range, LONG unit, LONG count, LONG ITextRange_GetEnd(range, &old_end); switch (unit) { + case tomCharacter: + { + ME_Cursor cursor; + LONG moved; + + ME_CursorFromCharOfs(editor, old_end, &cursor); + moved = ME_MoveCursorChars(editor, &cursor, count, TRUE); + new_start = old_start; + new_end = old_end + moved; + if (new_end < new_start) + new_start = new_end; + if (delta) + *delta = moved; + break; + } case tomStory: if (count < 0) new_start = new_end = 0; @@ -2260,7 +2318,7 @@ static HRESULT WINAPI ITextRange_fnMoveEnd(ITextRange *me, LONG unit, LONG count if (!This->child.reole) return CO_E_RELEASED; - return textrange_moveend(me, unit, count, delta); + return textrange_moveend(me, This->child.reole->editor, unit, count, delta); } static HRESULT WINAPI ITextRange_fnMoveWhile(ITextRange *me, VARIANT *charset, LONG count, @@ -4982,13 +5040,18 @@ static HRESULT WINAPI ITextSelection_fnMoveStart(ITextSelection *me, LONG unit, LONG *delta) { ITextSelectionImpl *This = impl_from_ITextSelection(me); + ITextRange *range = NULL; + HRESULT hr; - FIXME("(%p)->(%d %d %p): stub\n", This, unit, count, delta); + TRACE("(%p)->(%d %d %p)\n", This, unit, count, delta); if (!This->reOle) return CO_E_RELEASED; - return E_NOTIMPL; + ITextSelection_QueryInterface(me, &IID_ITextRange, (void**)&range); + hr = textrange_movestart(range, This->reOle->editor, unit, count, delta); + ITextRange_Release(range); + return hr; } static HRESULT WINAPI ITextSelection_fnMoveEnd(ITextSelection *me, LONG unit, LONG count, @@ -5004,7 +5067,7 @@ static HRESULT WINAPI ITextSelection_fnMoveEnd(ITextSelection *me, LONG unit, LO return CO_E_RELEASED; ITextSelection_QueryInterface(me, &IID_ITextRange, (void**)&range); - hr = textrange_moveend(range, unit, count, delta); + hr = textrange_moveend(range, This->reOle->editor, unit, count, delta); ITextRange_Release(range); return hr; } diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 70646202f0..5f903aa1ac 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -3694,7 +3694,7 @@ static void test_Expand(void) ITextRange_Release(range); } -static void test_MoveEnd(void) +static void test_MoveEnd_story(void) { static const char test_text1[] = "Word1 Word2"; IRichEditOle *reole = NULL; @@ -3808,6 +3808,99 @@ static void test_MoveEnd(void) ITextRange_Release(range); } +static void test_character_movestart(ITextRange *range, int textlen, int i, int j, LONG target) +{ + HRESULT hr; + LONG delta = 0; + LONG expected_delta; + LONG expected_start = target; + + if (expected_start < 0) + expected_start = 0; + else if (expected_start > textlen) + expected_start = textlen; + expected_delta = expected_start - i; + hr = ITextRange_SetRange(range, i, j); + ok(SUCCEEDED(hr), "got 0x%08x\n", hr); + hr = ITextRange_MoveStart(range, tomCharacter, target - i, &delta); + if (expected_start == i) { + ok(hr == S_FALSE, "(%d,%d) move by %d got hr=0x%08x\n", i, j, target - i, hr); + ok(delta == 0, "(%d,%d) move by %d got delta %d\n", i, j, target - i, delta); + CHECK_RANGE(range, i, j); + } else { + ok(hr == S_OK, "(%d,%d) move by %d got hr=0x%08x\n", i, j, target - i, hr); + ok(delta == expected_delta, "(%d,%d) move by %d got delta %d\n", i, j, target - i, delta); + if (expected_start <= j) + CHECK_RANGE(range, expected_start, j); + else + CHECK_RANGE(range, expected_start, expected_start); + } +} + +static void test_character_moveend(ITextRange *range, int textlen, int i, int j, LONG target) +{ + HRESULT hr; + LONG delta; + LONG expected_delta; + LONG expected_end = target; + + if (expected_end < 0) + expected_end = 0; + else if (expected_end > textlen + 1) + expected_end = textlen + 1; + expected_delta = expected_end - j; + hr = ITextRange_SetRange(range, i, j); + ok(SUCCEEDED(hr), "got 0x%08x\n", hr); + hr = ITextRange_MoveEnd(range, tomCharacter, target - j, &delta); + if (expected_end == j) { + ok(hr == S_FALSE, "(%d,%d) move by %d got hr=0x%08x\n", i, j, target - j, hr); + ok(delta == 0, "(%d,%d) move by %d got delta %d\n", i, j, target - j, delta); + CHECK_RANGE(range, i, j); + } else { + ok(hr == S_OK, "(%d,%d) move by %d got hr=0x%08x\n", i, j, target - j, hr); + ok(delta == expected_delta, "(%d,%d) move by %d got delta %d\n", i, j, target - j, delta); + if (i <= expected_end) + CHECK_RANGE(range, i, expected_end); + else + CHECK_RANGE(range, expected_end, expected_end); + } +} + +static void test_character_movement(void) +{ + static const char test_text1[] = "ab\n c"; + IRichEditOle *reole = NULL; + ITextDocument *doc = NULL; + ITextRange *range; + ITextSelection *selection; + HRESULT hr; + HWND hwnd; + int i, j; + const int textlen = strlen(test_text1); + + create_interfaces(&hwnd, &reole, &doc, &selection); + SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_text1); + + hr = ITextDocument_Range(doc, 0, 0, &range); + ok(hr == S_OK, "got 0x%08x\n", hr); + + /* Exhaustive test of every possible combination of (start,end) locations, + * against every possible target location to move to. */ + for (i = 0; i <= textlen; i++) { + for (j = i; j <= textlen; j++) { + LONG target; + for (target = -2; target <= textlen + 3; target++) { + test_character_moveend(range, textlen, i, j, target); + test_character_movestart(range, textlen, i, j, target); + } + } + } + + release_interfaces(&hwnd, &reole, &doc, NULL); + ITextSelection_Release(selection); + ITextRange_Release(range); +} + START_TEST(richole) { /* Must explicitly LoadLibrary(). The test has no references to functions in @@ -3846,5 +3939,6 @@ START_TEST(richole) test_GetStoryLength(); test_ITextSelection_GetDuplicate(); test_Expand(); - test_MoveEnd(); + test_MoveEnd_story(); + test_character_movement(); }