mshtml: Fixed spaces handling in range object.

This commit is contained in:
Jacek Caban 2007-10-21 15:47:53 +02:00 committed by Alexandre Julliard
parent 11d62d7fcb
commit cf19259a03
2 changed files with 195 additions and 75 deletions

View File

@ -32,7 +32,7 @@
static const char doc_blank[] = "<html></html>"; static const char doc_blank[] = "<html></html>";
static const char doc_str1[] = "<html><body>test</body></html>"; static const char doc_str1[] = "<html><body>test</body></html>";
static const char doc_str2[] = static const char doc_str2[] =
"<html><body>test a<font size=\"2\">bc 123<br />it's </font>text<br /></body></html>"; "<html><body>test \na<font size=\"2\">bc\t123<br /> it's\r\n \t</font>text<br /></body></html>";
static const char doc_str3[] = static const char doc_str3[] =
"<html><head><title>test</title><body>" "<html><head><title>test</title><body>"
"<a href=\"http://test\" name=\"x\">link</a><input />" "<a href=\"http://test\" name=\"x\">link</a><input />"
@ -876,6 +876,8 @@ static void test_txtrange(IHTMLDocument2 *doc)
test_range_parent(range, ET_BODY); test_range_parent(range, ET_BODY);
test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text"); test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text");
test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text"); test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text");
test_range_move(range, characterW, 3, 3);
test_range_expand(range, wordW, VARIANT_TRUE, "wordabc ");
IHTMLTxtRange_Release(range); IHTMLTxtRange_Release(range);
} }

View File

@ -185,6 +185,37 @@ static inline void wstrbuf_append(wstrbuf_t *buf, LPCWSTR str)
wstrbuf_append_len(buf, str, strlenW(str)); wstrbuf_append_len(buf, str, strlenW(str));
} }
static void wstrbuf_append_nodetxt(wstrbuf_t *buf, LPCWSTR str, int len)
{
const WCHAR *s = str;
WCHAR *d;
if(buf->len+len >= buf->size) {
buf->size = 2*buf->len+len;
buf->buf = mshtml_realloc(buf->buf, buf->size * sizeof(WCHAR));
}
if(buf->len && isspaceW(buf->buf[buf->len-1])) {
while(s < str+len && isspaceW(*s))
s++;
}
d = buf->buf+buf->len;
while(s < str+len) {
if(isspaceW(*s)) {
*d++ = ' ';
s++;
while(s < str+len && isspaceW(*s))
s++;
}else {
*d++ = *s++;
}
}
buf->len = d - buf->buf;
*d = 0;
}
static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node) static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
{ {
@ -199,7 +230,7 @@ static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
nsAString_Init(&data_str, NULL); nsAString_Init(&data_str, NULL);
nsIDOMText_GetData(nstext, &data_str); nsIDOMText_GetData(nstext, &data_str);
nsAString_GetData(&data_str, &data, NULL); nsAString_GetData(&data_str, &data, NULL);
wstrbuf_append(buf, data); wstrbuf_append_nodetxt(buf, data, strlenW(data));
nsAString_Finish(&data_str); nsAString_Finish(&data_str);
nsIDOMText_Release(nstext); nsIDOMText_Release(nstext);
@ -437,11 +468,11 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
if(start_pos.type == TEXT_NODE) { if(start_pos.type == TEXT_NODE) {
if(start_pos.node == end_pos.node) { if(start_pos.node == end_pos.node) {
wstrbuf_append_len(buf, start_pos.p+start_pos.off, end_pos.off-start_pos.off+1); wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, end_pos.off-start_pos.off+1);
iter = start_pos.node; iter = start_pos.node;
nsIDOMNode_AddRef(iter); nsIDOMNode_AddRef(iter);
}else { }else {
wstrbuf_append(buf, start_pos.p+start_pos.off); wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, strlenW(start_pos.p+start_pos.off));
iter = next_node(start_pos.node); iter = next_node(start_pos.node);
} }
}else { }else {
@ -459,11 +490,21 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
nsIDOMNode_AddRef(end_pos.node); nsIDOMNode_AddRef(end_pos.node);
if(start_pos.node != end_pos.node && !is_br_node(end_pos.node)) if(start_pos.node != end_pos.node && !is_br_node(end_pos.node))
wstrbuf_append_len(buf, end_pos.p, end_pos.off+1); wstrbuf_append_nodetxt(buf, end_pos.p, end_pos.off+1);
nsIDOMNode_Release(iter); nsIDOMNode_Release(iter);
dompos_release(&start_pos); dompos_release(&start_pos);
dompos_release(&end_pos); dompos_release(&end_pos);
if(buf->len) {
WCHAR *p;
for(p = buf->buf+buf->len-1; p >= buf->buf && isspaceW(*p); p--);
p = strchrW(p, '\r');
if(p)
*p = 0;
}
} }
static WCHAR get_pos_char(const dompos_t *pos) static WCHAR get_pos_char(const dompos_t *pos)
@ -482,77 +523,171 @@ static WCHAR get_pos_char(const dompos_t *pos)
static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos) static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos)
{ {
nsIDOMNode *iter, *tmp; nsIDOMNode *iter, *tmp;
dompos_t last_space, tmp_pos;
const WCHAR *p;
WCHAR cspace = 0;
if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off+1]) { if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off]) {
*new_pos = *pos; p = pos->p+pos->off+1;
new_pos->off++; if(*p && isspaceW(*p)) {
dompos_addref(new_pos); cspace = ' ';
return new_pos->p[new_pos->off]; while(p[1] && isspaceW(p[1]))
p++;
}
if(*p) {
*new_pos = *pos;
new_pos->off = p - pos->p;
dompos_addref(new_pos);
return *p;
}else {
last_space = *pos;
last_space.off = p - pos->p;
dompos_addref(&last_space);
}
} }
iter = next_node(pos->node); iter = next_node(pos->node);
if(!iter)
return 0;
while(1) { while(iter) {
switch(get_node_type(iter)) { switch(get_node_type(iter)) {
case TEXT_NODE: case TEXT_NODE:
new_pos->node = iter; tmp_pos.node = iter;
new_pos->type = TEXT_NODE; tmp_pos.type = TEXT_NODE;
new_pos->off = 0; dompos_addref(&tmp_pos);
fill_nodestr(new_pos);
return *new_pos->p; p = tmp_pos.p;
if(!*p) {
dompos_release(&tmp_pos);
break;
}else if(isspaceW(*p)) {
if(cspace)
dompos_release(&last_space);
else
cspace = ' ';
while(p[1] && isspaceW(p[1]))
p++;
tmp_pos.off = p-tmp_pos.p;
if(!p[1]) {
last_space = tmp_pos;
break;
}
*new_pos = tmp_pos;
nsIDOMNode_Release(iter);
return cspace;
}else if(cspace) {
*new_pos = last_space;
dompos_release(&tmp_pos);
nsIDOMNode_Release(iter);
return cspace;
}else if(*p) {
tmp_pos.off = 0;
*new_pos = tmp_pos;
}
nsIDOMNode_Release(iter);
return *p;
case ELEMENT_NODE: case ELEMENT_NODE:
if(!is_br_node(iter)) if(!is_br_node(iter))
break; break;
new_pos->node = iter; if(cspace)
new_pos->type = ELEMENT_NODE; dompos_release(&last_space);
new_pos->off = 0; cspace = '\n';
new_pos->p = NULL;
return '\n'; nsIDOMNode_AddRef(iter);
last_space.node = iter;
last_space.type = ELEMENT_NODE;
last_space.off = 0;
last_space.p = NULL;
} }
tmp = iter; tmp = iter;
iter = next_node(iter); iter = next_node(iter);
nsIDOMNode_Release(tmp); nsIDOMNode_Release(tmp);
if(!iter)
break;
} }
return 0; if(cspace) {
*new_pos = last_space;
}else {
*new_pos = *pos;
dompos_addref(new_pos);
}
return cspace;
} }
static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos) static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos)
{ {
nsIDOMNode *iter, *tmp; nsIDOMNode *iter, *tmp;
const WCHAR *p;
BOOL skip_space = FALSE;
if(pos->type == TEXT_NODE && pos->off > 0) { if(pos->type == TEXT_NODE && isspaceW(pos->p[pos->off]))
*new_pos = *pos; skip_space = TRUE;
new_pos->off--;
dompos_addref(new_pos); if(pos->type == TEXT_NODE && pos->off) {
return new_pos->p[new_pos->off]; p = pos->p+pos->off-1;
if(skip_space) {
while(p >= pos->p && isspace(*p))
p--;
}
if(p >= pos->p) {
*new_pos = *pos;
new_pos->off = p-pos->p;
dompos_addref(new_pos);
return new_pos->p[new_pos->off];
}
} }
iter = prev_node(This, pos->node); iter = prev_node(This, pos->node);
if(!iter)
return 0;
while(1) { while(iter) {
switch(get_node_type(iter)) { switch(get_node_type(iter)) {
case TEXT_NODE: case TEXT_NODE: {
new_pos->node = iter; dompos_t tmp_pos;
new_pos->type = TEXT_NODE;
fill_nodestr(new_pos); tmp_pos.node = iter;
new_pos->off = strlenW(new_pos->p)-1; tmp_pos.type = TEXT_NODE;
return new_pos->p[new_pos->off]; dompos_addref(&tmp_pos);
p = tmp_pos.p + strlenW(tmp_pos.p)-1;
if(skip_space) {
while(p >= tmp_pos.p && isspaceW(*p))
p--;
}
if(p < tmp_pos.p) {
dompos_release(&tmp_pos);
break;
}
tmp_pos.off = p-tmp_pos.p;
*new_pos = tmp_pos;
nsIDOMNode_Release(iter);
return *p;
}
case ELEMENT_NODE: case ELEMENT_NODE:
if(!is_br_node(iter)) if(!is_br_node(iter))
break; break;
if(skip_space) {
skip_space = FALSE;
break;
}
new_pos->node = iter; new_pos->node = iter;
new_pos->type = ELEMENT_NODE; new_pos->type = ELEMENT_NODE;
new_pos->off = 0; new_pos->off = 0;
@ -563,9 +698,6 @@ static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_po
tmp = iter; tmp = iter;
iter = prev_node(This, iter); iter = prev_node(This, iter);
nsIDOMNode_Release(tmp); nsIDOMNode_Release(tmp);
if(!iter)
break;
} }
*new_pos = *pos; *new_pos = *pos;
@ -598,12 +730,11 @@ static long move_next_chars(long cnt, const dompos_t *pos, BOOL col, const dompo
while(ret < cnt) { while(ret < cnt) {
tmp = iter; tmp = iter;
c = next_char(&tmp, &iter); c = next_char(&tmp, &iter);
if(!c) {
iter = tmp;
break;
}
ret++;
dompos_release(&tmp); dompos_release(&tmp);
if(!c)
break;
ret++;
if(bound_pos && dompos_cmp(&tmp, bound_pos)) { if(bound_pos && dompos_cmp(&tmp, bound_pos)) {
*bounded = TRUE; *bounded = TRUE;
ret++; ret++;
@ -631,15 +762,14 @@ static long move_prev_chars(HTMLTxtRange *This, long cnt, const dompos_t *pos, B
while(c && ret < cnt) { while(c && ret < cnt) {
tmp = iter; tmp = iter;
c = prev_char(This, &tmp, &iter); c = prev_char(This, &tmp, &iter);
dompos_release(&tmp);
if(!c) { if(!c) {
iter = tmp;
if(end) if(end)
ret++; ret++;
break; break;
} }
ret++; ret++;
dompos_release(&tmp);
if(bound_pos && dompos_cmp(&iter, bound_pos)) if(bound_pos && dompos_cmp(&iter, bound_pos))
*bounded = TRUE; *bounded = TRUE;
@ -649,34 +779,20 @@ static long move_prev_chars(HTMLTxtRange *This, long cnt, const dompos_t *pos, B
return ret; return ret;
} }
static BOOL find_next_space(const dompos_t *pos, BOOL first_space, dompos_t *ret) static BOOL find_next_space(const dompos_t *pos, dompos_t *ret)
{ {
dompos_t iter, tmp; dompos_t iter, tmp;
WCHAR c; 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); c = next_char(pos, &iter);
if(!c) { if(!c) {
*ret = *pos; *ret = iter;
dompos_addref(ret);
return FALSE; return FALSE;
} }
while(!isspaceW(c)) { while(c && !isspaceW(c)) {
tmp = iter; tmp = iter;
c = next_char(&tmp, &iter); c = next_char(&tmp, &iter);
if(!c) {
iter = tmp;
break;
}
dompos_release(&tmp); dompos_release(&tmp);
} }
@ -691,8 +807,7 @@ static long find_prev_space(HTMLTxtRange *This, const dompos_t *pos, BOOL first_
c = prev_char(This, pos, &iter); c = prev_char(This, pos, &iter);
if(!c || (first_space && isspaceW(c))) { if(!c || (first_space && isspaceW(c))) {
*ret = *pos; *ret = iter;
dompos_addref(ret);
return FALSE; return FALSE;
} }
@ -719,7 +834,7 @@ static long move_next_words(long cnt, const dompos_t *pos, dompos_t *new_pos)
dompos_addref(&iter); dompos_addref(&iter);
while(ret < cnt) { while(ret < cnt) {
if(!find_next_space(&iter, FALSE, &tmp)) if(!find_next_space(&iter, &tmp))
break; break;
ret++; ret++;
@ -1081,11 +1196,14 @@ static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIA
get_cur_pos(This, TRUE, &start_pos); get_cur_pos(This, TRUE, &start_pos);
get_cur_pos(This, FALSE, &end_pos); get_cur_pos(This, FALSE, &end_pos);
if(find_next_space(&end_pos, TRUE, &new_pos)) {
set_range_pos(This, FALSE, &new_pos); if(!isspaceW(get_pos_char(&end_pos))) {
*Success = VARIANT_TRUE; if(find_next_space(&end_pos, &new_pos)) {
set_range_pos(This, FALSE, &new_pos);
*Success = VARIANT_TRUE;
}
dompos_release(&new_pos);
} }
dompos_release(&new_pos);
if(find_prev_space(This, &start_pos, TRUE, &new_pos)) { if(find_prev_space(This, &start_pos, TRUE, &new_pos)) {
set_range_pos(This, TRUE, &new_pos); set_range_pos(This, TRUE, &new_pos);