mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 20:59:54 +00:00
mshtml: Reimplement IHTMLTxtRange::get_text.
This commit is contained in:
parent
85022e50c2
commit
1a7d41b739
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user