From efe323208784d5fce3ea5194efd74804308bdb8d Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Wed, 12 Sep 2007 23:32:46 +0200 Subject: [PATCH] mshtml: Added IHTMLTxtRange::expand implementation. --- dlls/mshtml/tests/dom.c | 18 +++ dlls/mshtml/txtrange.c | 263 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 279 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 0f883b3b287..f4a2f67f78b 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -33,6 +33,8 @@ static const char doc_str1[] = "test"; static const char doc_str2[] = "test abc 123
it's
text
"; +static WCHAR wordW[] = {'w','o','r','d',0}; + static const char *dbgstr_w(LPCWSTR str) { static char buf[512]; @@ -127,6 +129,19 @@ static void _test_range_collapse(unsigned line, IHTMLTxtRange *range, BOOL b) _test_range_text(line, range, NULL); } +#define test_range_expand(r,u,b,t) _test_range_expand(__LINE__,r,u,b,t) +static void _test_range_expand(unsigned line, IHTMLTxtRange *range, LPWSTR unit, + VARIANT_BOOL exb, const char *extext) +{ + VARIANT_BOOL b = 0xe0e0; + HRESULT hres; + + hres = IHTMLTxtRange_expand(range, unit, &b); + ok_(__FILE__,line) (hres == S_OK, "expand failed: %08x\n", hres); + ok_(__FILE__,line) (b == exb, "b=%x, expected %x\n", b, exb); + _test_range_text(line, range, extext); +} + #define test_range_inrange(r1,r2,b) _test_range_inrange(__LINE__,r1,r2,b) static void _test_range_inrange(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb) { @@ -196,6 +211,9 @@ static void test_txtrange(IHTMLDocument2 *doc) test_range_inrange(range2, range, VARIANT_TRUE); IHTMLTxtRange_Release(range2); + test_range_expand(range, wordW, VARIANT_TRUE, "test "); + test_range_expand(range, wordW, VARIANT_FALSE, "test "); + IHTMLTxtRange_Release(range); IHTMLTxtRange_Release(body_range); } diff --git a/dlls/mshtml/txtrange.c b/dlls/mshtml/txtrange.c index 99248e7d760..fdbaf9db8ca 100644 --- a/dlls/mshtml/txtrange.c +++ b/dlls/mshtml/txtrange.c @@ -65,6 +65,14 @@ typedef struct { const PRUnichar *p; } dompos_t; +typedef enum { + RU_UNKNOWN, + RU_CHAR, + RU_WORD, + RU_SENTENCE, + RU_TEXTEDIT +} range_unit_t; + static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface) { HTMLTxtRange *iter; @@ -78,6 +86,25 @@ static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface) return NULL; } +static range_unit_t string_to_unit(LPCWSTR str) +{ + static const WCHAR characterW[] = + {'c','h','a','r','a','c','t','e','r',0}; + static const WCHAR wordW[] = + {'w','o','r','d',0}; + static const WCHAR sentenceW[] = + {'s','e','n','t','e','n','c','e',0}; + static const WCHAR texteditW[] = + {'t','e','x','t','e','d','i','t',0}; + + if(!strcmpiW(str, characterW)) return RU_CHAR; + if(!strcmpiW(str, wordW)) return RU_WORD; + if(!strcmpiW(str, sentenceW)) return RU_SENTENCE; + if(!strcmpiW(str, texteditW)) return RU_TEXTEDIT; + + return RU_UNKNOWN; +} + static int string_to_nscmptype(LPCWSTR str) { static const WCHAR seW[] = {'S','t','a','r','t','T','o','E','n','d',0}; @@ -348,6 +375,26 @@ static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos) fill_nodestr(pos); } +static void set_range_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos) +{ + nsresult nsres; + + if(start) { + if(pos->type == TEXT_NODE) + nsres = nsIDOMRange_SetStart(This->nsrange, pos->node, pos->off); + else + nsres = nsIDOMRange_SetStartBefore(This->nsrange, pos->node); + }else { + if(pos->type == TEXT_NODE) + nsres = nsIDOMRange_SetEnd(This->nsrange, pos->node, pos->off+1); + else + nsres = nsIDOMRange_SetEndAfter(This->nsrange, pos->node); + } + + if(NS_FAILED(nsres)) + ERR("failed: %p %08x\n", pos->node, nsres); +} + static void inline dompos_release(dompos_t *pos) { if(pos->node) @@ -357,6 +404,15 @@ static void inline dompos_release(dompos_t *pos) nsAString_Finish(&pos->str); } +static void inline dompos_addref(dompos_t *pos) +{ + if(pos->node) + nsIDOMNode_AddRef(pos->node); + + if(pos->type == TEXT_NODE) + fill_nodestr(pos); +} + static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf) { nsIDOMNode *iter, *tmp; @@ -405,6 +461,174 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf) dompos_release(&end_pos); } +static WCHAR get_pos_char(const dompos_t *pos) +{ + switch(pos->type) { + case TEXT_NODE: + return pos->p[pos->off]; + case ELEMENT_NODE: + if(is_br_node(pos->node)) + return '\n'; + } + + return 0; +} + +static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos) +{ + nsIDOMNode *iter, *tmp; + + if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off+1]) { + *new_pos = *pos; + new_pos->off++; + dompos_addref(new_pos); + return new_pos->p[new_pos->off]; + } + + iter = next_node(pos->node); + if(!iter) + return 0; + + while(1) { + switch(get_node_type(iter)) { + case TEXT_NODE: + new_pos->node = iter; + new_pos->type = TEXT_NODE; + new_pos->off = 0; + fill_nodestr(new_pos); + return *new_pos->p; + + case ELEMENT_NODE: + if(!is_br_node(iter)) + break; + + new_pos->node = iter; + new_pos->type = ELEMENT_NODE; + new_pos->off = 0; + new_pos->p = NULL; + return '\n'; + } + + tmp = iter; + iter = next_node(iter); + nsIDOMNode_Release(tmp); + + if(!iter) + break; + } + + return 0; +} + +static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos) +{ + nsIDOMNode *iter, *tmp; + + if(pos->type == TEXT_NODE && pos->off > 0) { + *new_pos = *pos; + new_pos->off--; + dompos_addref(new_pos); + return new_pos->p[new_pos->off]; + } + + iter = prev_node(This, pos->node); + if(!iter) + return 0; + + while(1) { + switch(get_node_type(iter)) { + case TEXT_NODE: + new_pos->node = iter; + new_pos->type = TEXT_NODE; + fill_nodestr(new_pos); + new_pos->off = strlenW(new_pos->p)-1; + return new_pos->p[new_pos->off]; + + case ELEMENT_NODE: + if(!is_br_node(iter)) + break; + + new_pos->node = iter; + new_pos->type = ELEMENT_NODE; + new_pos->off = 0; + new_pos->p = NULL; + return '\n'; + } + + tmp = iter; + iter = prev_node(This, iter); + nsIDOMNode_Release(tmp); + + if(!iter) + break; + } + + *new_pos = *pos; + dompos_addref(new_pos); + return 0; +} + +static BOOL find_next_space(const dompos_t *pos, BOOL first_space, dompos_t *ret) +{ + dompos_t iter, tmp; + WCHAR c; + + if(first_space) { + c = get_pos_char(pos); + if(c && isspaceW(c)) { + *ret = *pos; + dompos_addref(ret); + return FALSE; + } + } + + c = next_char(pos, &iter); + if(!c) { + *ret = *pos; + dompos_addref(ret); + return FALSE; + } + + while(!isspaceW(c)) { + tmp = iter; + c = next_char(&tmp, &iter); + if(!c) { + iter = tmp; + break; + } + dompos_release(&tmp); + } + + *ret = iter; + return TRUE; +} + +static long find_prev_space(HTMLTxtRange *This, const dompos_t *pos, BOOL first_space, dompos_t *ret) +{ + dompos_t iter, tmp; + WCHAR c; + + c = prev_char(This, pos, &iter); + if(!c || (first_space && isspaceW(c))) { + *ret = *pos; + dompos_addref(ret); + return FALSE; + } + + while(1) { + tmp = iter; + c = prev_char(This, &tmp, &iter); + if(!c || isspaceW(c)) { + dompos_release(&iter); + break; + } + dompos_release(&tmp); + } + + *ret = tmp; + return TRUE; +} + #define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface) static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv) @@ -715,8 +939,43 @@ static HRESULT WINAPI HTMLTxtRange_collapse(IHTMLTxtRange *iface, VARIANT_BOOL S static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIANT_BOOL *Success) { HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); - FIXME("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success); - return E_NOTIMPL; + range_unit_t unit; + + TRACE("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success); + + unit = string_to_unit(Unit); + if(unit == RU_UNKNOWN) + return E_INVALIDARG; + + switch(unit) { + case RU_WORD: { + dompos_t end_pos, start_pos, new_pos; + + *Success = VARIANT_FALSE; + + get_cur_pos(This, TRUE, &start_pos); + get_cur_pos(This, FALSE, &end_pos); + if(find_next_space(&end_pos, TRUE, &new_pos)) { + set_range_pos(This, FALSE, &new_pos); + *Success = VARIANT_TRUE; + } + dompos_release(&new_pos); + + if(find_prev_space(This, &start_pos, TRUE, &new_pos)) { + set_range_pos(This, TRUE, &new_pos); + *Success = VARIANT_TRUE; + } + + dompos_release(&new_pos); + dompos_release(&end_pos); + + break; + } + default: + FIXME("Unimplemented unit %s\n", debugstr_w(Unit)); + } + + return S_OK; } static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit,