Jacek Caban : mshtml: Introduced new representation of range point and use that in range_to_string instead of trying to iterate by nodes.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Dec 29 15:42:42 CST 2014


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Dec 29 15:49:31 2014 +0100

mshtml: Introduced new representation of range point and use that in range_to_string instead of trying to iterate by nodes.

---

 dlls/mshtml/txtrange.c | 220 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 173 insertions(+), 47 deletions(-)

diff --git a/dlls/mshtml/txtrange.c b/dlls/mshtml/txtrange.c
index 0dd3aae..c6fba3e 100644
--- a/dlls/mshtml/txtrange.c
+++ b/dlls/mshtml/txtrange.c
@@ -59,6 +59,12 @@ typedef struct {
     UINT16 type;
     nsIDOMNode *node;
     UINT32 off;
+} rangepoint_t;
+
+typedef struct {
+    UINT16 type;
+    nsIDOMNode *node;
+    UINT32 off;
     nsAString str;
     const PRUnichar *p;
 } dompos_t;
@@ -128,6 +134,136 @@ static UINT16 get_node_type(nsIDOMNode *node)
     return type;
 }
 
+static void get_text_node_data(nsIDOMNode *node, nsAString *nsstr, const PRUnichar **str)
+{
+    nsIDOMText *nstext;
+    nsresult nsres;
+
+    nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMText, (void**)&nstext);
+    assert(nsres == NS_OK);
+
+    nsAString_Init(nsstr, NULL);
+    nsres = nsIDOMText_GetData(nstext, nsstr);
+    nsIDOMText_Release(nstext);
+    if(NS_FAILED(nsres))
+        ERR("GetData failed: %08x\n", nsres);
+
+    nsAString_GetData(nsstr, str);
+}
+
+static nsIDOMNode *get_child_node(nsIDOMNode *node, UINT32 off)
+{
+    nsIDOMNodeList *node_list;
+    nsIDOMNode *ret = NULL;
+
+    nsIDOMNode_GetChildNodes(node, &node_list);
+    nsIDOMNodeList_Item(node_list, off, &ret);
+    nsIDOMNodeList_Release(node_list);
+
+    return ret;
+}
+
+/* This is very inefficient, but there is no faster way to compute index in
+ * child node list using public API. Gecko has internal nsINode::IndexOf
+ * function that we could consider exporting and use instead. */
+static int get_child_index(nsIDOMNode *parent, nsIDOMNode *child)
+{
+    nsIDOMNodeList *node_list;
+    nsIDOMNode *node;
+    int ret = 0;
+    nsresult nsres;
+
+    nsres = nsIDOMNode_GetChildNodes(parent, &node_list);
+    assert(nsres == NS_OK);
+
+    while(1) {
+        nsres = nsIDOMNodeList_Item(node_list, ret, &node);
+        assert(nsres == NS_OK && node);
+        if(node == child) {
+            nsIDOMNode_Release(node);
+            break;
+        }
+        nsIDOMNode_Release(node);
+        ret++;
+    }
+
+    nsIDOMNodeList_Release(node_list);
+    return ret;
+}
+
+static void init_rangepoint(rangepoint_t *rangepoint, nsIDOMNode *node, UINT32 off)
+{
+    nsIDOMNode_AddRef(node);
+
+    rangepoint->type = get_node_type(node);
+    rangepoint->node = node;
+    rangepoint->off = off;
+}
+
+static inline void free_rangepoint(rangepoint_t *rangepoint)
+{
+    nsIDOMNode_Release(rangepoint->node);
+}
+
+static inline BOOL rangepoint_cmp(const rangepoint_t *point1, const rangepoint_t *point2)
+{
+    return point1->node == point2->node && point1->off == point2->off;
+}
+
+static BOOL rangepoint_next_node(rangepoint_t *iter)
+{
+    nsIDOMNode *node;
+    UINT32 off;
+    nsresult nsres;
+
+    /* Try to move to the child node. */
+    node = get_child_node(iter->node, iter->off);
+    if(node) {
+        free_rangepoint(iter);
+        init_rangepoint(iter, node, 0);
+        nsIDOMNode_Release(node);
+        return TRUE;
+    }
+
+    /* There are no more children in the node. Move to parent. */
+    nsres = nsIDOMNode_GetParentNode(iter->node, &node);
+    assert(nsres == NS_OK);
+    if(!node)
+        return FALSE;
+
+    off = get_child_index(node, iter->node)+1;
+    free_rangepoint(iter);
+    init_rangepoint(iter, node, off);
+    nsIDOMNode_Release(node);
+    return TRUE;
+}
+
+static void get_start_point(HTMLTxtRange *This, rangepoint_t *ret)
+{
+    nsIDOMNode *node;
+    LONG off;
+
+    nsIDOMRange_GetStartContainer(This->nsrange, &node);
+    nsIDOMRange_GetStartOffset(This->nsrange, &off);
+
+    init_rangepoint(ret, node, off);
+
+    nsIDOMNode_Release(node);
+}
+
+static void get_end_point(HTMLTxtRange *This, rangepoint_t *ret)
+{
+    nsIDOMNode *node;
+    LONG off;
+
+    nsIDOMRange_GetEndContainer(This->nsrange, &node);
+    nsIDOMRange_GetEndOffset(This->nsrange, &off);
+
+    init_rangepoint(ret, node, off);
+
+    nsIDOMNode_Release(node);
+}
+
 static BOOL is_elem_tag(nsIDOMNode *node, LPCWSTR istag)
 {
     nsIDOMElement *elem;
@@ -236,7 +372,7 @@ static void wstrbuf_append_nodetxt(wstrbuf_t *buf, LPCWSTR str, int len)
     *d = 0;
 }
 
-static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
+static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node, BOOL ignore_text)
 {
 
     switch(get_node_type(node)) {
@@ -245,6 +381,9 @@ static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
         nsAString data_str;
         const PRUnichar *data;
 
+        if(ignore_text)
+            break;
+
         nsIDOMNode_QueryInterface(node, &IID_nsIDOMText, (void**)&nstext);
 
         nsAString_Init(&data_str, NULL);
@@ -272,7 +411,7 @@ static void wstrbuf_append_node_rec(wstrbuf_t *buf, nsIDOMNode *node)
 {
     nsIDOMNode *iter, *tmp;
 
-    wstrbuf_append_node(buf, node);
+    wstrbuf_append_node(buf, node, FALSE);
 
     nsIDOMNode_GetFirstChild(node, &iter);
     while(iter) {
@@ -379,18 +518,6 @@ static nsIDOMNode *prev_node(HTMLTxtRange *This, nsIDOMNode *iter)
     return NULL;
 }
 
-static nsIDOMNode *get_child_node(nsIDOMNode *node, UINT32 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;
@@ -485,8 +612,7 @@ static inline BOOL dompos_cmp(const dompos_t *pos1, const dompos_t *pos2)
 
 static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
 {
-    nsIDOMNode *iter, *tmp;
-    dompos_t start_pos, end_pos;
+    rangepoint_t end_pos, iter;
     cpp_bool collapsed;
 
     nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
@@ -497,42 +623,42 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
         return;
     }
 
-    get_cur_pos(This, FALSE, &end_pos);
-    get_cur_pos(This, TRUE, &start_pos);
+    get_end_point(This, &end_pos);
+    get_start_point(This, &iter);
 
-    if(start_pos.type == TEXT_NODE) {
-        if(start_pos.node == end_pos.node) {
-            wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, end_pos.off-start_pos.off+1);
-            iter = start_pos.node;
-            nsIDOMNode_AddRef(iter);
-        }else {
-            wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, strlenW(start_pos.p+start_pos.off));
-            iter = next_node(start_pos.node);
-        }
-    }else {
-        iter = start_pos.node;
-        nsIDOMNode_AddRef(iter);
-    }
+    do {
+        if(iter.type == TEXT_NODE) {
+            const PRUnichar *str;
+            nsAString nsstr;
 
-    while(iter != end_pos.node) {
-        wstrbuf_append_node(buf, iter);
-        tmp = next_node(iter);
-        nsIDOMNode_Release(iter);
-        iter = tmp;
-    }
+            get_text_node_data(iter.node, &nsstr, &str);
 
-    nsIDOMNode_AddRef(end_pos.node);
+            if(iter.node == end_pos.node) {
+                wstrbuf_append_nodetxt(buf, str+iter.off, end_pos.off-iter.off);
+                nsAString_Finish(&nsstr);
+                break;
+            }
 
-    if(start_pos.node != end_pos.node) {
-        if(end_pos.type == TEXT_NODE)
-            wstrbuf_append_nodetxt(buf, end_pos.p, end_pos.off+1);
-        else
-            wstrbuf_append_node(buf, end_pos.node);
-    }
+            wstrbuf_append_nodetxt(buf, str+iter.off, strlenW(str+iter.off));
+            nsAString_Finish(&nsstr);
+        }else {
+            nsIDOMNode *node;
+
+            node = get_child_node(iter.node, iter.off);
+            if(node) {
+                wstrbuf_append_node(buf, node, TRUE);
+                nsIDOMNode_Release(node);
+            }
+        }
+
+        if(!rangepoint_next_node(&iter)) {
+            ERR("End of document?\n");
+            break;
+        }
+    }while(!rangepoint_cmp(&iter, &end_pos));
 
-    nsIDOMNode_Release(iter);
-    dompos_release(&start_pos);
-    dompos_release(&end_pos);
+    free_rangepoint(&iter);
+    free_rangepoint(&end_pos);
 
     if(buf->len) {
         WCHAR *p;




More information about the wine-cvs mailing list