Jacek Caban : mshtml: Added IHTMLTxtRange::expand implementation.

Alexandre Julliard julliard at winehq.org
Thu Sep 13 07:17:23 CDT 2007


Module: wine
Branch: master
Commit: efe323208784d5fce3ea5194efd74804308bdb8d
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=efe323208784d5fce3ea5194efd74804308bdb8d

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Sep 12 23:32:46 2007 +0200

mshtml: Added IHTMLTxtRange::expand implementation.

---

 dlls/mshtml/tests/dom.c |   18 +++
 dlls/mshtml/txtrange.c  |  263 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 279 insertions(+), 2 deletions(-)

diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c
index 0f883b3..f4a2f67 100644
--- a/dlls/mshtml/tests/dom.c
+++ b/dlls/mshtml/tests/dom.c
@@ -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);
 }
diff --git a/dlls/mshtml/txtrange.c b/dlls/mshtml/txtrange.c
index 99248e7..fdbaf9d 100644
--- a/dlls/mshtml/txtrange.c
+++ b/dlls/mshtml/txtrange.c
@@ -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,




More information about the wine-cvs mailing list