mshtml: Use new range point representation in all cases.

This commit is contained in:
Jacek Caban 2014-12-29 15:50:22 +01:00 committed by Alexandre Julliard
parent 4ef4ebaac7
commit 00d36ac945
1 changed files with 24 additions and 647 deletions

View File

@ -61,14 +61,6 @@ typedef struct {
UINT32 off;
} rangepoint_t;
typedef struct {
UINT16 type;
nsIDOMNode *node;
UINT32 off;
nsAString str;
const PRUnichar *p;
} dompos_t;
typedef enum {
RU_UNKNOWN,
RU_CHAR,
@ -364,30 +356,6 @@ static BOOL is_elem_tag(nsIDOMNode *node, LPCWSTR istag)
return ret;
}
static BOOL is_space_elem(nsIDOMNode *node)
{
nsIDOMElement *elem;
nsAString tag_str;
const PRUnichar *tag;
BOOL ret = FALSE;
nsresult nsres;
nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem);
if(NS_FAILED(nsres))
return FALSE;
nsAString_Init(&tag_str, NULL);
nsIDOMElement_GetTagName(elem, &tag_str);
nsIDOMElement_Release(elem);
nsAString_GetData(&tag_str, &tag);
ret = !strcmpiW(tag, brW) || !strcmpiW(tag, hrW);
nsAString_Finish(&tag_str);
return ret;
}
static inline BOOL wstrbuf_init(wstrbuf_t *buf)
{
buf->len = 0;
@ -498,194 +466,6 @@ static void wstrbuf_append_node_rec(wstrbuf_t *buf, nsIDOMNode *node)
}
}
static BOOL fill_nodestr(dompos_t *pos)
{
nsIDOMText *text;
nsresult nsres;
if(pos->type != TEXT_NODE)
return FALSE;
nsres = nsIDOMNode_QueryInterface(pos->node, &IID_nsIDOMText, (void**)&text);
if(NS_FAILED(nsres))
return FALSE;
nsAString_Init(&pos->str, NULL);
nsIDOMText_GetData(text, &pos->str);
nsIDOMText_Release(text);
nsAString_GetData(&pos->str, &pos->p);
if(pos->off == -1)
pos->off = *pos->p ? strlenW(pos->p)-1 : 0;
return TRUE;
}
static nsIDOMNode *next_node(nsIDOMNode *iter)
{
nsIDOMNode *ret, *tmp;
nsresult nsres;
if(!iter)
return NULL;
nsres = nsIDOMNode_GetFirstChild(iter, &ret);
if(NS_SUCCEEDED(nsres) && ret)
return ret;
nsIDOMNode_AddRef(iter);
do {
nsres = nsIDOMNode_GetNextSibling(iter, &ret);
if(NS_SUCCEEDED(nsres) && ret) {
nsIDOMNode_Release(iter);
return ret;
}
nsres = nsIDOMNode_GetParentNode(iter, &tmp);
nsIDOMNode_Release(iter);
iter = tmp;
}while(NS_SUCCEEDED(nsres) && iter);
return NULL;
}
static nsIDOMNode *prev_node(HTMLTxtRange *This, nsIDOMNode *iter)
{
nsIDOMNode *ret, *tmp;
nsresult nsres;
if(!iter) {
nsIDOMHTMLElement *nselem;
nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nselem);
nsIDOMHTMLElement_GetLastChild(nselem, &tmp);
if(!tmp)
return (nsIDOMNode*)nselem;
while(tmp) {
ret = tmp;
nsIDOMNode_GetLastChild(ret, &tmp);
}
nsIDOMHTMLElement_Release(nselem);
return ret;
}
nsres = nsIDOMNode_GetLastChild(iter, &ret);
if(NS_SUCCEEDED(nsres) && ret)
return ret;
nsIDOMNode_AddRef(iter);
do {
nsres = nsIDOMNode_GetPreviousSibling(iter, &ret);
if(NS_SUCCEEDED(nsres) && ret) {
nsIDOMNode_Release(iter);
return ret;
}
nsres = nsIDOMNode_GetParentNode(iter, &tmp);
nsIDOMNode_Release(iter);
iter = tmp;
}while(NS_SUCCEEDED(nsres) && iter);
return NULL;
}
static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
{
nsIDOMNode *node;
LONG off;
pos->p = NULL;
if(!start) {
cpp_bool collapsed;
nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
start = collapsed;
}
if(start) {
nsIDOMRange_GetStartContainer(This->nsrange, &node);
nsIDOMRange_GetStartOffset(This->nsrange, &off);
}else {
nsIDOMRange_GetEndContainer(This->nsrange, &node);
nsIDOMRange_GetEndOffset(This->nsrange, &off);
}
pos->type = get_node_type(node);
if(pos->type == ELEMENT_NODE) {
if(start) {
pos->node = get_child_node(node, off);
pos->off = 0;
}else {
pos->node = off ? get_child_node(node, off-1) : prev_node(This, node);
pos->off = -1;
}
pos->type = get_node_type(pos->node);
nsIDOMNode_Release(node);
}else if(start) {
pos->node = node;
pos->off = off;
}else if(off) {
pos->node = node;
pos->off = off-1;
}else {
pos->node = prev_node(This, node);
pos->off = -1;
nsIDOMNode_Release(node);
}
if(pos->type == TEXT_NODE)
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 && pos->p[pos->off+1])
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 inline void dompos_release(dompos_t *pos)
{
if(pos->node)
nsIDOMNode_Release(pos->node);
if(pos->p)
nsAString_Finish(&pos->str);
}
static inline void dompos_addref(dompos_t *pos)
{
if(pos->node)
nsIDOMNode_AddRef(pos->node);
if(pos->type == TEXT_NODE)
fill_nodestr(pos);
}
static inline BOOL dompos_cmp(const dompos_t *pos1, const dompos_t *pos2)
{
return pos1->node == pos2->node && pos1->off == pos2->off;
}
static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
{
rangepoint_t end_pos, iter;
@ -1017,394 +797,22 @@ static BOOL find_word_end(rangepoint_t *iter, BOOL is_collapsed)
return ret;
}
static WCHAR get_pos_char(const dompos_t *pos)
static LONG move_by_words(rangepoint_t *iter, LONG cnt)
{
switch(pos->type) {
case TEXT_NODE:
return pos->p[pos->off];
case ELEMENT_NODE:
if(is_space_elem(pos->node))
return '\n';
}
return 0;
}
static void end_space(const dompos_t *pos, dompos_t *new_pos)
{
const WCHAR *p;
*new_pos = *pos;
dompos_addref(new_pos);
if(pos->type != TEXT_NODE)
return;
p = new_pos->p+new_pos->off;
if(!*p || !isspace(*p))
return;
while(p[1] && isspace(p[1]))
p++;
new_pos->off = p - new_pos->p;
}
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]) {
p = pos->p+pos->off;
if(isspace(*p))
while(isspaceW(*++p));
else
p++;
if(*p && isspaceW(*p)) {
cspace = ' ';
while(p[1] && isspaceW(p[1]))
p++;
}
if(*p) {
*new_pos = *pos;
new_pos->off = p - pos->p;
dompos_addref(new_pos);
return cspace ? cspace : *p;
}else {
last_space = *pos;
last_space.off = p - pos->p;
dompos_addref(&last_space);
}
}
iter = next_node(pos->node);
while(iter) {
switch(get_node_type(iter)) {
case TEXT_NODE:
tmp_pos.node = iter;
tmp_pos.type = TEXT_NODE;
tmp_pos.off = 0;
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_elem_tag(iter, brW)) {
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;
}else if(is_elem_tag(iter, hrW)) {
if(cspace) {
*new_pos = last_space;
nsIDOMNode_Release(iter);
return cspace;
}
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(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 && 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 = p-pos->p;
dompos_addref(new_pos);
return new_pos->p[new_pos->off];
}
}
iter = prev_node(This, pos->node);
while(iter) {
switch(get_node_type(iter)) {
case TEXT_NODE: {
dompos_t tmp_pos;
tmp_pos.node = iter;
tmp_pos.type = TEXT_NODE;
tmp_pos.off = 0;
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_elem_tag(iter, brW)) {
if(skip_space) {
skip_space = FALSE;
break;
}
}else if(!is_elem_tag(iter, hrW)) {
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);
}
*new_pos = *pos;
dompos_addref(new_pos);
return 0;
}
static LONG move_next_chars(LONG cnt, const dompos_t *pos, BOOL col, const dompos_t *bound_pos,
BOOL *bounded, dompos_t *new_pos)
{
dompos_t iter, tmp;
LONG ret = 0;
WCHAR c;
if(bounded)
*bounded = FALSE;
if(cnt >= 0) {
WCHAR c;
if(col)
ret++;
if(ret >= cnt) {
end_space(pos, new_pos);
return ret;
}
c = next_char(pos, &iter);
ret++;
while(ret < cnt) {
tmp = iter;
c = next_char(&tmp, &iter);
dompos_release(&tmp);
if(!c)
break;
ret++;
if(bound_pos && dompos_cmp(&tmp, bound_pos)) {
*bounded = TRUE;
ret++;
}
}
*new_pos = iter;
return ret;
}
static LONG move_prev_chars(HTMLTxtRange *This, LONG cnt, const dompos_t *pos, BOOL end,
const dompos_t *bound_pos, BOOL *bounded, dompos_t *new_pos)
{
dompos_t iter, tmp;
LONG ret = 0;
BOOL prev_eq = FALSE;
WCHAR c;
if(bounded)
*bounded = FALSE;
c = prev_char(This, pos, &iter);
if(c)
ret++;
while(c && ret < cnt) {
tmp = iter;
c = prev_char(This, &tmp, &iter);
dompos_release(&tmp);
if(!c) {
if(end)
while(ret < cnt && (c = move_next_char(iter))) {
if(isspaceW(c))
ret++;
break;
}
ret++;
if(prev_eq) {
*bounded = TRUE;
ret++;
}
prev_eq = bound_pos && dompos_cmp(&iter, bound_pos);
}
*new_pos = iter;
return ret;
}
static LONG dompos_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 = iter;
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;
}
static LONG move_next_words(LONG cnt, const dompos_t *pos, dompos_t *new_pos)
{
dompos_t iter, tmp;
LONG ret = 0;
WCHAR c;
c = get_pos_char(pos);
if(isspaceW(c)) {
end_space(pos, &iter);
ret++;
}else {
c = next_char(pos, &iter);
if(c && isspaceW(c))
ret++;
while(ret > cnt && find_prev_space(iter, FALSE))
ret--;
}
while(c && ret < cnt) {
tmp = iter;
c = next_char(&tmp, &iter);
dompos_release(&tmp);
if(isspaceW(c))
ret++;
}
*new_pos = iter;
return ret;
}
static LONG move_prev_words(HTMLTxtRange *This, LONG cnt, const dompos_t *pos, dompos_t *new_pos)
{
dompos_t iter, tmp;
LONG ret = 0;
iter = *pos;
dompos_addref(&iter);
while(ret < cnt) {
if(!dompos_find_prev_space(This, &iter, FALSE, &tmp))
break;
dompos_release(&iter);
iter = tmp;
ret++;
}
*new_pos = iter;
return ret;
}
@ -1804,45 +1212,28 @@ static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit,
switch(unit) {
case RU_CHAR: {
dompos_t cur_pos, new_pos;
rangepoint_t start;
get_cur_pos(This, TRUE, &cur_pos);
get_start_point(This, &start);
if(Count > 0) {
*ActualCount = move_next_chars(Count, &cur_pos, TRUE, NULL, NULL, &new_pos);
set_range_pos(This, FALSE, &new_pos);
dompos_release(&new_pos);
*ActualCount = move_by_chars(&start, Count);
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, FALSE);
}else {
*ActualCount = -move_prev_chars(This, -Count, &cur_pos, FALSE, NULL, NULL, &new_pos);
set_range_pos(This, TRUE, &new_pos);
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, TRUE);
dompos_release(&new_pos);
}
dompos_release(&cur_pos);
set_start_point(This, &start);
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, TRUE);
free_rangepoint(&start);
break;
}
case RU_WORD: {
dompos_t cur_pos, new_pos;
rangepoint_t start;
get_cur_pos(This, TRUE, &cur_pos);
get_start_point(This, &start);
if(Count > 0) {
*ActualCount = move_next_words(Count, &cur_pos, &new_pos);
set_range_pos(This, FALSE, &new_pos);
dompos_release(&new_pos);
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, FALSE);
}else {
*ActualCount = -move_prev_words(This, -Count, &cur_pos, &new_pos);
set_range_pos(This, TRUE, &new_pos);
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, TRUE);
dompos_release(&new_pos);
}
*ActualCount = move_by_words(&start, Count);
dompos_release(&cur_pos);
set_start_point(This, &start);
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, TRUE);
free_rangepoint(&start);
break;
}
@ -1911,28 +1302,14 @@ static HRESULT WINAPI HTMLTxtRange_moveEnd(IHTMLTxtRange *iface, BSTR Unit,
switch(unit) {
case RU_CHAR: {
dompos_t start_pos, end_pos, new_pos;
cpp_bool collapsed;
rangepoint_t end;
get_cur_pos(This, TRUE, &start_pos);
get_cur_pos(This, FALSE, &end_pos);
nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
get_end_point(This, &end);
if(Count > 0) {
*ActualCount = move_next_chars(Count, &end_pos, collapsed, NULL, NULL, &new_pos);
set_range_pos(This, FALSE, &new_pos);
}else {
BOOL bounded;
*ActualCount = move_by_chars(&end, Count);
*ActualCount = -move_prev_chars(This, -Count, &end_pos, TRUE, &start_pos, &bounded, &new_pos);
set_range_pos(This, bounded, &new_pos);
if(bounded)
IHTMLTxtRange_collapse(&This->IHTMLTxtRange_iface, TRUE);
}
dompos_release(&start_pos);
dompos_release(&end_pos);
dompos_release(&new_pos);
set_end_point(This, &end);
free_rangepoint(&end);
break;
}