mshtml: Reimplement IHTMLTxtRange::get_text.

This commit is contained in:
Jacek Caban 2007-09-12 23:17:31 +02:00 committed by Alexandre Julliard
parent 85022e50c2
commit 1a7d41b739

View File

@ -36,6 +36,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
static const WCHAR brW[] = {'b','r',0};
typedef struct {
const IHTMLTxtRangeVtbl *lpHTMLTxtRangeVtbl;
@ -49,6 +51,20 @@ typedef struct {
#define HTMLTXTRANGE(x) ((IHTMLTxtRange*) &(x)->lpHTMLTxtRangeVtbl)
typedef struct {
WCHAR *buf;
DWORD len;
DWORD size;
} wstrbuf_t;
typedef struct {
PRUint16 type;
nsIDOMNode *node;
PRUint32 off;
nsAString str;
const PRUnichar *p;
} dompos_t;
static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface)
{
HTMLTxtRange *iter;
@ -87,6 +103,308 @@ static PRUint16 get_node_type(nsIDOMNode *node)
return type;
}
static BOOL is_br_node(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, 0);
if(!strcmpiW(tag, brW))
ret = TRUE;
nsAString_Finish(&tag_str);
return ret;
}
static void inline wstrbuf_init(wstrbuf_t *buf)
{
buf->len = 0;
buf->size = 16;
buf->buf = mshtml_alloc(buf->size * sizeof(WCHAR));
*buf->buf = 0;
}
static void inline wstrbuf_finish(wstrbuf_t *buf)
{
mshtml_free(buf->buf);
}
static void wstrbuf_append_len(wstrbuf_t *buf, LPCWSTR str, int len)
{
if(buf->len+len >= buf->size) {
buf->size = 2*buf->len+len;
buf->buf = mshtml_realloc(buf->buf, buf->size * sizeof(WCHAR));
}
memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
buf->len += len;
buf->buf[buf->len] = 0;
}
static void inline wstrbuf_append(wstrbuf_t *buf, LPCWSTR str)
{
wstrbuf_append_len(buf, str, strlenW(str));
}
static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
{
switch(get_node_type(node)) {
case TEXT_NODE: {
nsIDOMText *nstext;
nsAString data_str;
const PRUnichar *data;
nsIDOMNode_QueryInterface(node, &IID_nsIDOMText, (void**)&nstext);
nsAString_Init(&data_str, NULL);
nsIDOMText_GetData(nstext, &data_str);
nsAString_GetData(&data_str, &data, NULL);
wstrbuf_append(buf, data);
nsAString_Finish(&data_str);
nsIDOMText_Release(nstext);
break;
}
case ELEMENT_NODE:
if(is_br_node(node)) {
static const WCHAR endlW[] = {'\r','\n'};
wstrbuf_append_len(buf, endlW, 2);
}
}
}
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, NULL);
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) {
nsIDOMHTMLDocument *nshtmldoc;
nsIDOMHTMLElement *nselem;
nsIDOMDocument *nsdoc;
nsIWebNavigation_GetDocument(This->doc->nscontainer->navigation, &nsdoc);
nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMHTMLDocument, (void**)&nshtmldoc);
nsIDOMDocument_Release(nsdoc);
nsIDOMHTMLDocument_GetBody(nshtmldoc, &nselem);
nsIDOMHTMLDocument_Release(nshtmldoc);
nsIDOMElement_GetLastChild(nselem, &tmp);
if(!tmp)
return (nsIDOMNode*)nselem;
while(tmp) {
ret = tmp;
nsIDOMNode_GetLastChild(ret, &tmp);
}
nsIDOMElement_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 nsIDOMNode *get_child_node(nsIDOMNode *node, PRUint32 off)
{
nsIDOMNodeList *node_list;
nsIDOMNode *ret = NULL;
nsIDOMNode_GetChildNodes(node, &node_list);
nsIDOMNodeList_Item(node_list, off, &ret);
nsIDOMNodeList_Release(node_list);
return ret;
}
static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
{
nsIDOMNode *node;
PRInt32 off;
pos->p = NULL;
if(!start) {
PRBool 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 inline dompos_release(dompos_t *pos)
{
if(pos->node)
nsIDOMNode_Release(pos->node);
if(pos->p)
nsAString_Finish(&pos->str);
}
static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
{
nsIDOMNode *iter, *tmp;
dompos_t start_pos, end_pos;
PRBool collapsed;
nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
if(collapsed) {
wstrbuf_finish(buf);
buf->buf = NULL;
buf->size = 0;
return;
}
get_cur_pos(This, FALSE, &end_pos);
get_cur_pos(This, TRUE, &start_pos);
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);
iter = start_pos.node;
nsIDOMNode_AddRef(iter);
}else {
wstrbuf_append(buf, start_pos.p+start_pos.off);
iter = next_node(start_pos.node);
}
}else {
iter = start_pos.node;
nsIDOMNode_AddRef(iter);
}
while(iter != end_pos.node) {
wstrbuf_append_node(buf, iter);
tmp = next_node(iter);
nsIDOMNode_Release(iter);
iter = tmp;
}
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);
nsIDOMNode_Release(iter);
dompos_release(&start_pos);
dompos_release(&end_pos);
}
#define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface)
static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv)
@ -255,35 +573,19 @@ static HRESULT WINAPI HTMLTxtRange_put_text(IHTMLTxtRange *iface, BSTR v)
static HRESULT WINAPI HTMLTxtRange_get_text(IHTMLTxtRange *iface, BSTR *p)
{
HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
wstrbuf_t buf;
TRACE("(%p)->(%p)\n", This, p);
*p = NULL;
if(This->nsrange) {
nsAString text_str;
nsresult nsres;
nsAString_Init(&text_str, NULL);
nsres = nsIDOMRange_ToString(This->nsrange, &text_str);
if(NS_SUCCEEDED(nsres)) {
const PRUnichar *nstext;
nsAString_GetData(&text_str, &nstext, NULL);
*p = SysAllocString(nstext);
}else {
ERR("ToString failed: %08x\n", nsres);
}
nsAString_Finish(&text_str);
}
if(!*p) {
static const WCHAR empty[] = {0};
*p = SysAllocString(empty);
}
wstrbuf_init(&buf);
range_to_string(This, &buf);
if(buf.buf)
*p = SysAllocString(buf.buf);
else
*p = NULL;
wstrbuf_finish(&buf);
TRACE("ret %s\n", debugstr_w(*p));
return S_OK;
}