mshtml: Fixed spaces handling in range object.
This commit is contained in:
parent
11d62d7fcb
commit
cf19259a03
|
@ -32,7 +32,7 @@
|
|||
static const char doc_blank[] = "<html></html>";
|
||||
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>";
|
||||
"<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[] =
|
||||
"<html><head><title>test</title><body>"
|
||||
"<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_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);
|
||||
}
|
||||
|
|
|
@ -185,6 +185,37 @@ static inline void wstrbuf_append(wstrbuf_t *buf, LPCWSTR 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)
|
||||
{
|
||||
|
||||
|
@ -199,7 +230,7 @@ static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
|
|||
nsAString_Init(&data_str, NULL);
|
||||
nsIDOMText_GetData(nstext, &data_str);
|
||||
nsAString_GetData(&data_str, &data, NULL);
|
||||
wstrbuf_append(buf, data);
|
||||
wstrbuf_append_nodetxt(buf, data, strlenW(data));
|
||||
nsAString_Finish(&data_str);
|
||||
|
||||
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.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;
|
||||
nsIDOMNode_AddRef(iter);
|
||||
}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);
|
||||
}
|
||||
}else {
|
||||
|
@ -459,11 +490,21 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
|
|||
nsIDOMNode_AddRef(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);
|
||||
dompos_release(&start_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)
|
||||
|
@ -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)
|
||||
{
|
||||
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]) {
|
||||
p = pos->p+pos->off+1;
|
||||
if(*p && isspaceW(*p)) {
|
||||
cspace = ' ';
|
||||
while(p[1] && isspaceW(p[1]))
|
||||
p++;
|
||||
}
|
||||
|
||||
if(*p) {
|
||||
*new_pos = *pos;
|
||||
new_pos->off++;
|
||||
new_pos->off = p - pos->p;
|
||||
dompos_addref(new_pos);
|
||||
return new_pos->p[new_pos->off];
|
||||
|
||||
return *p;
|
||||
}else {
|
||||
last_space = *pos;
|
||||
last_space.off = p - pos->p;
|
||||
dompos_addref(&last_space);
|
||||
}
|
||||
}
|
||||
|
||||
iter = next_node(pos->node);
|
||||
if(!iter)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
while(iter) {
|
||||
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;
|
||||
tmp_pos.node = iter;
|
||||
tmp_pos.type = TEXT_NODE;
|
||||
dompos_addref(&tmp_pos);
|
||||
|
||||
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:
|
||||
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';
|
||||
if(cspace)
|
||||
dompos_release(&last_space);
|
||||
cspace = '\n';
|
||||
|
||||
nsIDOMNode_AddRef(iter);
|
||||
last_space.node = iter;
|
||||
last_space.type = ELEMENT_NODE;
|
||||
last_space.off = 0;
|
||||
last_space.p = NULL;
|
||||
}
|
||||
|
||||
tmp = iter;
|
||||
iter = next_node(iter);
|
||||
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)
|
||||
{
|
||||
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]))
|
||||
skip_space = TRUE;
|
||||
|
||||
if(pos->type == TEXT_NODE && 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--;
|
||||
new_pos->off = p-pos->p;
|
||||
dompos_addref(new_pos);
|
||||
return new_pos->p[new_pos->off];
|
||||
}
|
||||
}
|
||||
|
||||
iter = prev_node(This, pos->node);
|
||||
if(!iter)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
while(iter) {
|
||||
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 TEXT_NODE: {
|
||||
dompos_t tmp_pos;
|
||||
|
||||
tmp_pos.node = iter;
|
||||
tmp_pos.type = TEXT_NODE;
|
||||
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:
|
||||
if(!is_br_node(iter))
|
||||
break;
|
||||
|
||||
if(skip_space) {
|
||||
skip_space = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
new_pos->node = iter;
|
||||
new_pos->type = ELEMENT_NODE;
|
||||
new_pos->off = 0;
|
||||
|
@ -563,9 +698,6 @@ static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_po
|
|||
tmp = iter;
|
||||
iter = prev_node(This, iter);
|
||||
nsIDOMNode_Release(tmp);
|
||||
|
||||
if(!iter)
|
||||
break;
|
||||
}
|
||||
|
||||
*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) {
|
||||
tmp = iter;
|
||||
c = next_char(&tmp, &iter);
|
||||
if(!c) {
|
||||
iter = tmp;
|
||||
break;
|
||||
}
|
||||
ret++;
|
||||
dompos_release(&tmp);
|
||||
if(!c)
|
||||
break;
|
||||
|
||||
ret++;
|
||||
if(bound_pos && dompos_cmp(&tmp, bound_pos)) {
|
||||
*bounded = TRUE;
|
||||
ret++;
|
||||
|
@ -631,15 +762,14 @@ static long move_prev_chars(HTMLTxtRange *This, long cnt, const dompos_t *pos, B
|
|||
while(c && ret < cnt) {
|
||||
tmp = iter;
|
||||
c = prev_char(This, &tmp, &iter);
|
||||
dompos_release(&tmp);
|
||||
if(!c) {
|
||||
iter = tmp;
|
||||
if(end)
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
|
||||
ret++;
|
||||
dompos_release(&tmp);
|
||||
|
||||
if(bound_pos && dompos_cmp(&iter, bound_pos))
|
||||
*bounded = TRUE;
|
||||
|
@ -649,34 +779,20 @@ static long move_prev_chars(HTMLTxtRange *This, long cnt, const dompos_t *pos, B
|
|||
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;
|
||||
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);
|
||||
*ret = iter;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(!isspaceW(c)) {
|
||||
while(c && !isspaceW(c)) {
|
||||
tmp = iter;
|
||||
c = next_char(&tmp, &iter);
|
||||
if(!c) {
|
||||
iter = tmp;
|
||||
break;
|
||||
}
|
||||
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);
|
||||
if(!c || (first_space && isspaceW(c))) {
|
||||
*ret = *pos;
|
||||
dompos_addref(ret);
|
||||
*ret = iter;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -719,7 +834,7 @@ static long move_next_words(long cnt, const dompos_t *pos, dompos_t *new_pos)
|
|||
dompos_addref(&iter);
|
||||
|
||||
while(ret < cnt) {
|
||||
if(!find_next_space(&iter, FALSE, &tmp))
|
||||
if(!find_next_space(&iter, &tmp))
|
||||
break;
|
||||
|
||||
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, FALSE, &end_pos);
|
||||
if(find_next_space(&end_pos, TRUE, &new_pos)) {
|
||||
|
||||
if(!isspaceW(get_pos_char(&end_pos))) {
|
||||
if(find_next_space(&end_pos, &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);
|
||||
|
|
Loading…
Reference in New Issue