<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Aug 17, 2020 at 12:02 PM Huw Davies <<a href="mailto:huw@codeweavers.com">huw@codeweavers.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Mon, Aug 17, 2020 at 05:22:57AM +0200, Damjan Jovanovic wrote:<br>
> Signed-off-by: Damjan Jovanovic <<a href="mailto:damjan.jov@gmail.com" target="_blank">damjan.jov@gmail.com</a>><br>
> ---<br>
> dlls/riched20/richole.c | 77 +++++++++++++++++++++++++--<br>
> dlls/riched20/tests/richole.c | 98 ++++++++++++++++++++++++++++++++++-<br>
> 2 files changed, 169 insertions(+), 6 deletions(-)<br>
<br>
> diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c<br>
> index 7c281ab364..1fd307eb92 100644<br>
> --- a/dlls/riched20/richole.c<br>
> +++ b/dlls/riched20/richole.c<br>
> @@ -2191,17 +2191,63 @@ static HRESULT WINAPI ITextRange_fnMove(ITextRange *me, LONG unit, LONG count, L<br>
> return E_NOTIMPL;<br>
> }<br>
> <br>
> +static HRESULT textrange_movestart(ITextRange *range, LONG unit, LONG count, LONG *delta)<br>
> +{<br>
> + LONG old_start, old_end, new_start, new_end;<br>
> + HRESULT hr = S_OK;<br>
> +<br>
> + if (!count)<br>
> + {<br>
> + if (delta)<br>
> + *delta = 0;<br>
> + return S_FALSE;<br>
> + }<br>
> +<br>
> + ITextRange_GetStart(range, &old_start);<br>
> + ITextRange_GetEnd(range, &old_end);<br>
> + switch (unit)<br>
> + {<br>
> + case tomCharacter:<br>
> + {<br>
> + ME_TextEditor *editor;<br>
> + ME_Cursor cursor;<br>
> + LONG moved;<br>
> + ITextRangeImpl *This = impl_from_ITextRange(range);<br>
> + editor = This->child.reole->editor;<br>
> +<br>
> + ME_CursorFromCharOfs(editor, old_start, &cursor);<br>
> + moved = ME_MoveCursorChars(editor, &cursor, count, FALSE);<br>
> + new_start = old_start + moved;<br>
> + new_end = old_end;<br>
> + if (new_end < new_start)<br>
> + new_end = new_start;<br>
> + if (delta)<br>
> + *delta = moved;<br>
> + break;<br>
> + }<br>
> + default:<br>
> + FIXME("unit %d is not supported\n", unit);<br>
> + return E_NOTIMPL;<br>
> + }<br>
> + if (new_start == old_start)<br>
> + hr = S_FALSE;<br>
> + ITextRange_SetStart(range, new_start);<br>
> + ITextRange_SetEnd(range, new_end);<br>
> +<br>
> + return hr;<br>
> +}<br>
> +<br>
> static HRESULT WINAPI ITextRange_fnMoveStart(ITextRange *me, LONG unit, LONG count,<br>
> LONG *delta)<br>
> {<br>
> ITextRangeImpl *This = impl_from_ITextRange(me);<br>
> <br>
> - FIXME("(%p)->(%d %d %p): stub\n", This, unit, count, delta);<br>
> + TRACE("(%p)->(%d %d %p)\n", This, unit, count, delta);<br>
> <br>
> if (!This->child.reole)<br>
> return CO_E_RELEASED;<br>
> <br>
> - return E_NOTIMPL;<br>
> + return textrange_movestart(me, unit, count, delta);<br>
> }<br>
<br>
I know textrange_moveend() is a thing, but it's not clear why.<br>
I think all of the implementation of MoveStart should go in<br>
ITextRange_fnMoveStart, then ITextSelection_fnMoveStart would call<br>
ITextRage_MoveStart().<br>
<br></blockquote><div><br></div><div>I tried that. Unfortunately ITextSelection_fnQueryInterface() implements IID_ITextRange by returning itself, resulting in ITextSelection_fnMoveEnd() calling itself until the stack overflows.</div><div><br></div><div>ITextRange and ITextSelection are on separate objects, we can't QI from the one to the other. Using a common textrange_moveend() style function independent of the objects, seems like the only way. Sadly even those functions are wrong in my patches, because they cannot call impl_from_ITextRange() on an ITextSelection. I think the calling functions could pass them whatever they need from their impl, such as ME_TextEditor*.<br></div><div><br></div><div>New patches will take a while.</div><br></div></div>