mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
mshtml: Added IHTMLTxtRange::expand implementation.
This commit is contained in:
parent
6859de16f6
commit
efe3232087
2 changed files with 279 additions and 2 deletions
|
@ -33,6 +33,8 @@ 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>";
|
||||
|
||||
static WCHAR wordW[] = {'w','o','r','d',0};
|
||||
|
||||
static const char *dbgstr_w(LPCWSTR str)
|
||||
{
|
||||
static char buf[512];
|
||||
|
@ -127,6 +129,19 @@ static void _test_range_collapse(unsigned line, IHTMLTxtRange *range, BOOL b)
|
|||
_test_range_text(line, range, NULL);
|
||||
}
|
||||
|
||||
#define test_range_expand(r,u,b,t) _test_range_expand(__LINE__,r,u,b,t)
|
||||
static void _test_range_expand(unsigned line, IHTMLTxtRange *range, LPWSTR unit,
|
||||
VARIANT_BOOL exb, const char *extext)
|
||||
{
|
||||
VARIANT_BOOL b = 0xe0e0;
|
||||
HRESULT hres;
|
||||
|
||||
hres = IHTMLTxtRange_expand(range, unit, &b);
|
||||
ok_(__FILE__,line) (hres == S_OK, "expand failed: %08x\n", hres);
|
||||
ok_(__FILE__,line) (b == exb, "b=%x, expected %x\n", b, exb);
|
||||
_test_range_text(line, range, extext);
|
||||
}
|
||||
|
||||
#define test_range_inrange(r1,r2,b) _test_range_inrange(__LINE__,r1,r2,b)
|
||||
static void _test_range_inrange(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb)
|
||||
{
|
||||
|
@ -196,6 +211,9 @@ static void test_txtrange(IHTMLDocument2 *doc)
|
|||
test_range_inrange(range2, range, VARIANT_TRUE);
|
||||
IHTMLTxtRange_Release(range2);
|
||||
|
||||
test_range_expand(range, wordW, VARIANT_TRUE, "test ");
|
||||
test_range_expand(range, wordW, VARIANT_FALSE, "test ");
|
||||
|
||||
IHTMLTxtRange_Release(range);
|
||||
IHTMLTxtRange_Release(body_range);
|
||||
}
|
||||
|
|
|
@ -65,6 +65,14 @@ typedef struct {
|
|||
const PRUnichar *p;
|
||||
} dompos_t;
|
||||
|
||||
typedef enum {
|
||||
RU_UNKNOWN,
|
||||
RU_CHAR,
|
||||
RU_WORD,
|
||||
RU_SENTENCE,
|
||||
RU_TEXTEDIT
|
||||
} range_unit_t;
|
||||
|
||||
static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface)
|
||||
{
|
||||
HTMLTxtRange *iter;
|
||||
|
@ -78,6 +86,25 @@ static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static range_unit_t string_to_unit(LPCWSTR str)
|
||||
{
|
||||
static const WCHAR characterW[] =
|
||||
{'c','h','a','r','a','c','t','e','r',0};
|
||||
static const WCHAR wordW[] =
|
||||
{'w','o','r','d',0};
|
||||
static const WCHAR sentenceW[] =
|
||||
{'s','e','n','t','e','n','c','e',0};
|
||||
static const WCHAR texteditW[] =
|
||||
{'t','e','x','t','e','d','i','t',0};
|
||||
|
||||
if(!strcmpiW(str, characterW)) return RU_CHAR;
|
||||
if(!strcmpiW(str, wordW)) return RU_WORD;
|
||||
if(!strcmpiW(str, sentenceW)) return RU_SENTENCE;
|
||||
if(!strcmpiW(str, texteditW)) return RU_TEXTEDIT;
|
||||
|
||||
return RU_UNKNOWN;
|
||||
}
|
||||
|
||||
static int string_to_nscmptype(LPCWSTR str)
|
||||
{
|
||||
static const WCHAR seW[] = {'S','t','a','r','t','T','o','E','n','d',0};
|
||||
|
@ -348,6 +375,26 @@ static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
|
|||
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)
|
||||
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 void inline dompos_release(dompos_t *pos)
|
||||
{
|
||||
if(pos->node)
|
||||
|
@ -357,6 +404,15 @@ static void inline dompos_release(dompos_t *pos)
|
|||
nsAString_Finish(&pos->str);
|
||||
}
|
||||
|
||||
static void inline dompos_addref(dompos_t *pos)
|
||||
{
|
||||
if(pos->node)
|
||||
nsIDOMNode_AddRef(pos->node);
|
||||
|
||||
if(pos->type == TEXT_NODE)
|
||||
fill_nodestr(pos);
|
||||
}
|
||||
|
||||
static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
|
||||
{
|
||||
nsIDOMNode *iter, *tmp;
|
||||
|
@ -405,6 +461,174 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
|
|||
dompos_release(&end_pos);
|
||||
}
|
||||
|
||||
static WCHAR get_pos_char(const dompos_t *pos)
|
||||
{
|
||||
switch(pos->type) {
|
||||
case TEXT_NODE:
|
||||
return pos->p[pos->off];
|
||||
case ELEMENT_NODE:
|
||||
if(is_br_node(pos->node))
|
||||
return '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos)
|
||||
{
|
||||
nsIDOMNode *iter, *tmp;
|
||||
|
||||
if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off+1]) {
|
||||
*new_pos = *pos;
|
||||
new_pos->off++;
|
||||
dompos_addref(new_pos);
|
||||
return new_pos->p[new_pos->off];
|
||||
}
|
||||
|
||||
iter = next_node(pos->node);
|
||||
if(!iter)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
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;
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
tmp = iter;
|
||||
iter = next_node(iter);
|
||||
nsIDOMNode_Release(tmp);
|
||||
|
||||
if(!iter)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos)
|
||||
{
|
||||
nsIDOMNode *iter, *tmp;
|
||||
|
||||
if(pos->type == TEXT_NODE && pos->off > 0) {
|
||||
*new_pos = *pos;
|
||||
new_pos->off--;
|
||||
dompos_addref(new_pos);
|
||||
return new_pos->p[new_pos->off];
|
||||
}
|
||||
|
||||
iter = prev_node(This, pos->node);
|
||||
if(!iter)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
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 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';
|
||||
}
|
||||
|
||||
tmp = iter;
|
||||
iter = prev_node(This, iter);
|
||||
nsIDOMNode_Release(tmp);
|
||||
|
||||
if(!iter)
|
||||
break;
|
||||
}
|
||||
|
||||
*new_pos = *pos;
|
||||
dompos_addref(new_pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL find_next_space(const dompos_t *pos, BOOL first_space, 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);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(!isspaceW(c)) {
|
||||
tmp = iter;
|
||||
c = next_char(&tmp, &iter);
|
||||
if(!c) {
|
||||
iter = tmp;
|
||||
break;
|
||||
}
|
||||
dompos_release(&tmp);
|
||||
}
|
||||
|
||||
*ret = iter;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static long 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 = *pos;
|
||||
dompos_addref(ret);
|
||||
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;
|
||||
}
|
||||
|
||||
#define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface)
|
||||
|
||||
static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv)
|
||||
|
@ -715,8 +939,43 @@ static HRESULT WINAPI HTMLTxtRange_collapse(IHTMLTxtRange *iface, VARIANT_BOOL S
|
|||
static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIANT_BOOL *Success)
|
||||
{
|
||||
HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
|
||||
FIXME("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success);
|
||||
return E_NOTIMPL;
|
||||
range_unit_t unit;
|
||||
|
||||
TRACE("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success);
|
||||
|
||||
unit = string_to_unit(Unit);
|
||||
if(unit == RU_UNKNOWN)
|
||||
return E_INVALIDARG;
|
||||
|
||||
switch(unit) {
|
||||
case RU_WORD: {
|
||||
dompos_t end_pos, start_pos, new_pos;
|
||||
|
||||
*Success = VARIANT_FALSE;
|
||||
|
||||
get_cur_pos(This, TRUE, &start_pos);
|
||||
get_cur_pos(This, FALSE, &end_pos);
|
||||
if(find_next_space(&end_pos, TRUE, &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);
|
||||
*Success = VARIANT_TRUE;
|
||||
}
|
||||
|
||||
dompos_release(&new_pos);
|
||||
dompos_release(&end_pos);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FIXME("Unimplemented unit %s\n", debugstr_w(Unit));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit,
|
||||
|
|
Loading…
Reference in a new issue