mshtml: Added IHTMLTxtRange::expand implementation.

This commit is contained in:
Jacek Caban 2007-09-12 23:32:46 +02:00 committed by Alexandre Julliard
parent 6859de16f6
commit efe3232087
2 changed files with 279 additions and 2 deletions

View file

@ -33,6 +33,8 @@ static const char doc_str1[] = "<html><body>test</body></html>";
static const char doc_str2[] =
"<html><body>test a<font size=\"2\">bc 123<br />it's </font>text<br /></body></html>";
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);
}

View file

@ -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,