ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

txtrange.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2006-2007 Jacek Caban for CodeWeavers
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include <stdarg.h>
00020 
00021 #define COBJMACROS
00022 
00023 #include "windef.h"
00024 #include "winbase.h"
00025 #include "winuser.h"
00026 #include "ole2.h"
00027 #include "mshtmcid.h"
00028 
00029 #include "wine/debug.h"
00030 #include "wine/unicode.h"
00031 
00032 #include "mshtml_private.h"
00033 
00034 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
00035 
00036 static const WCHAR brW[] = {'b','r',0};
00037 static const WCHAR hrW[] = {'h','r',0};
00038 
00039 typedef struct {
00040     const IHTMLTxtRangeVtbl *lpHTMLTxtRangeVtbl;
00041     const IOleCommandTargetVtbl *lpOleCommandTargetVtbl;
00042 
00043     LONG ref;
00044 
00045     nsIDOMRange *nsrange;
00046     HTMLDocumentNode *doc;
00047 
00048     struct list entry;
00049 } HTMLTxtRange;
00050 
00051 #define HTMLTXTRANGE(x)  ((IHTMLTxtRange*)  &(x)->lpHTMLTxtRangeVtbl)
00052 
00053 typedef struct {
00054     WCHAR *buf;
00055     DWORD len;
00056     DWORD size;
00057 } wstrbuf_t;
00058 
00059 typedef struct {
00060     PRUint16 type;
00061     nsIDOMNode *node;
00062     PRUint32 off;
00063     nsAString str;
00064     const PRUnichar *p;
00065 } dompos_t;
00066 
00067 typedef enum {
00068     RU_UNKNOWN,
00069     RU_CHAR,
00070     RU_WORD,
00071     RU_SENTENCE,
00072     RU_TEXTEDIT
00073 } range_unit_t;
00074 
00075 static HTMLTxtRange *get_range_object(HTMLDocumentNode *doc, IHTMLTxtRange *iface)
00076 {
00077     HTMLTxtRange *iter;
00078 
00079     LIST_FOR_EACH_ENTRY(iter, &doc->range_list, HTMLTxtRange, entry) {
00080         if(HTMLTXTRANGE(iter) == iface)
00081             return iter;
00082     }
00083 
00084     ERR("Could not find range in document\n");
00085     return NULL;
00086 }
00087 
00088 static range_unit_t string_to_unit(LPCWSTR str)
00089 {
00090     static const WCHAR characterW[] =
00091         {'c','h','a','r','a','c','t','e','r',0};
00092     static const WCHAR wordW[] =
00093         {'w','o','r','d',0};
00094     static const WCHAR sentenceW[] =
00095         {'s','e','n','t','e','n','c','e',0};
00096     static const WCHAR texteditW[] =
00097         {'t','e','x','t','e','d','i','t',0};
00098 
00099     if(!strcmpiW(str, characterW))  return RU_CHAR;
00100     if(!strcmpiW(str, wordW))       return RU_WORD;
00101     if(!strcmpiW(str, sentenceW))   return RU_SENTENCE;
00102     if(!strcmpiW(str, texteditW))   return RU_TEXTEDIT;
00103 
00104     return RU_UNKNOWN;
00105 }
00106 
00107 static int string_to_nscmptype(LPCWSTR str)
00108 {
00109     static const WCHAR seW[] = {'S','t','a','r','t','T','o','E','n','d',0};
00110     static const WCHAR ssW[] = {'S','t','a','r','t','T','o','S','t','a','r','t',0};
00111     static const WCHAR esW[] = {'E','n','d','T','o','S','t','a','r','t',0};
00112     static const WCHAR eeW[] = {'E','n','d','T','o','E','n','d',0};
00113 
00114     if(!strcmpiW(str, seW))  return NS_START_TO_END;
00115     if(!strcmpiW(str, ssW))  return NS_START_TO_START;
00116     if(!strcmpiW(str, esW))  return NS_END_TO_START;
00117     if(!strcmpiW(str, eeW))  return NS_END_TO_END;
00118 
00119     return -1;
00120 }
00121 
00122 static PRUint16 get_node_type(nsIDOMNode *node)
00123 {
00124     PRUint16 type = 0;
00125 
00126     if(node)
00127         nsIDOMNode_GetNodeType(node, &type);
00128 
00129     return type;
00130 }
00131 
00132 static BOOL is_elem_tag(nsIDOMNode *node, LPCWSTR istag)
00133 {
00134     nsIDOMElement *elem;
00135     nsAString tag_str;
00136     const PRUnichar *tag;
00137     BOOL ret = FALSE;
00138     nsresult nsres;
00139 
00140     nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem);
00141     if(NS_FAILED(nsres))
00142         return FALSE;
00143 
00144     nsAString_Init(&tag_str, NULL);
00145     nsIDOMElement_GetTagName(elem, &tag_str);
00146     nsIDOMElement_Release(elem);
00147     nsAString_GetData(&tag_str, &tag);
00148 
00149     ret = !strcmpiW(tag, istag);
00150 
00151     nsAString_Finish(&tag_str);
00152 
00153     return ret;
00154 }
00155 
00156 static BOOL is_space_elem(nsIDOMNode *node)
00157 {
00158     nsIDOMElement *elem;
00159     nsAString tag_str;
00160     const PRUnichar *tag;
00161     BOOL ret = FALSE;
00162     nsresult nsres;
00163 
00164     nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem);
00165     if(NS_FAILED(nsres))
00166         return FALSE;
00167 
00168     nsAString_Init(&tag_str, NULL);
00169     nsIDOMElement_GetTagName(elem, &tag_str);
00170     nsIDOMElement_Release(elem);
00171     nsAString_GetData(&tag_str, &tag);
00172 
00173     ret = !strcmpiW(tag, brW) || !strcmpiW(tag, hrW);
00174 
00175     nsAString_Finish(&tag_str);
00176 
00177     return ret;
00178 }
00179 
00180 static inline BOOL wstrbuf_init(wstrbuf_t *buf)
00181 {
00182     buf->len = 0;
00183     buf->size = 16;
00184     buf->buf = heap_alloc(buf->size * sizeof(WCHAR));
00185     if (!buf->buf) return FALSE;
00186     *buf->buf = 0;
00187     return TRUE;
00188 }
00189 
00190 static inline void wstrbuf_finish(wstrbuf_t *buf)
00191 {
00192     heap_free(buf->buf);
00193 }
00194 
00195 static void wstrbuf_append_len(wstrbuf_t *buf, LPCWSTR str, int len)
00196 {
00197     if(buf->len+len >= buf->size) {
00198         buf->size = 2*buf->size+len;
00199         buf->buf = heap_realloc(buf->buf, buf->size * sizeof(WCHAR));
00200     }
00201 
00202     memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
00203     buf->len += len;
00204     buf->buf[buf->len] = 0;
00205 }
00206 
00207 static void wstrbuf_append_nodetxt(wstrbuf_t *buf, LPCWSTR str, int len)
00208 {
00209     const WCHAR *s = str;
00210     WCHAR *d;
00211 
00212     TRACE("%s\n", debugstr_wn(str, len));
00213 
00214     if(buf->len+len >= buf->size) {
00215         buf->size = 2*buf->size+len;
00216         buf->buf = heap_realloc(buf->buf, buf->size * sizeof(WCHAR));
00217     }
00218 
00219     if(buf->len && isspaceW(buf->buf[buf->len-1])) {
00220         while(s < str+len && isspaceW(*s))
00221             s++;
00222     }
00223 
00224     d = buf->buf+buf->len;
00225     while(s < str+len) {
00226         if(isspaceW(*s)) {
00227             *d++ = ' ';
00228             s++;
00229             while(s < str+len && isspaceW(*s))
00230                 s++;
00231         }else {
00232             *d++ = *s++;
00233         }
00234     }
00235 
00236     buf->len = d - buf->buf;
00237     *d = 0;
00238 }
00239 
00240 static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
00241 {
00242 
00243     switch(get_node_type(node)) {
00244     case TEXT_NODE: {
00245         nsIDOMText *nstext;
00246         nsAString data_str;
00247         const PRUnichar *data;
00248 
00249         nsIDOMNode_QueryInterface(node, &IID_nsIDOMText, (void**)&nstext);
00250 
00251         nsAString_Init(&data_str, NULL);
00252         nsIDOMText_GetData(nstext, &data_str);
00253         nsAString_GetData(&data_str, &data);
00254         wstrbuf_append_nodetxt(buf, data, strlenW(data));
00255         nsAString_Finish(&data_str);
00256 
00257         nsIDOMText_Release(nstext);
00258 
00259         break;
00260     }
00261     case ELEMENT_NODE:
00262         if(is_elem_tag(node, brW)) {
00263             static const WCHAR endlW[] = {'\r','\n'};
00264             wstrbuf_append_len(buf, endlW, 2);
00265         }else if(is_elem_tag(node, hrW)) {
00266             static const WCHAR endl2W[] = {'\r','\n','\r','\n'};
00267             wstrbuf_append_len(buf, endl2W, 4);
00268         }
00269     }
00270 }
00271 
00272 static void wstrbuf_append_node_rec(wstrbuf_t *buf, nsIDOMNode *node)
00273 {
00274     nsIDOMNode *iter, *tmp;
00275 
00276     wstrbuf_append_node(buf, node);
00277 
00278     nsIDOMNode_GetFirstChild(node, &iter);
00279     while(iter) {
00280         wstrbuf_append_node_rec(buf, iter);
00281         nsIDOMNode_GetNextSibling(iter, &tmp);
00282         nsIDOMNode_Release(iter);
00283         iter = tmp;
00284     }
00285 }
00286 
00287 static BOOL fill_nodestr(dompos_t *pos)
00288 {
00289     nsIDOMText *text;
00290     nsresult nsres;
00291 
00292     if(pos->type != TEXT_NODE)
00293         return FALSE;
00294 
00295     nsres = nsIDOMNode_QueryInterface(pos->node, &IID_nsIDOMText, (void**)&text);
00296     if(NS_FAILED(nsres))
00297         return FALSE;
00298 
00299     nsAString_Init(&pos->str, NULL);
00300     nsIDOMText_GetData(text, &pos->str);
00301     nsIDOMText_Release(text);
00302     nsAString_GetData(&pos->str, &pos->p);
00303 
00304     if(pos->off == -1)
00305         pos->off = *pos->p ? strlenW(pos->p)-1 : 0;
00306 
00307     return TRUE;
00308 }
00309 
00310 static nsIDOMNode *next_node(nsIDOMNode *iter)
00311 {
00312     nsIDOMNode *ret, *tmp;
00313     nsresult nsres;
00314 
00315     if(!iter)
00316         return NULL;
00317 
00318     nsres = nsIDOMNode_GetFirstChild(iter, &ret);
00319     if(NS_SUCCEEDED(nsres) && ret)
00320         return ret;
00321 
00322     nsIDOMNode_AddRef(iter);
00323 
00324     do {
00325         nsres = nsIDOMNode_GetNextSibling(iter, &ret);
00326         if(NS_SUCCEEDED(nsres) && ret) {
00327             nsIDOMNode_Release(iter);
00328             return ret;
00329         }
00330 
00331         nsres = nsIDOMNode_GetParentNode(iter, &tmp);
00332         nsIDOMNode_Release(iter);
00333         iter = tmp;
00334     }while(NS_SUCCEEDED(nsres) && iter);
00335 
00336     return NULL;
00337 }
00338 
00339 static nsIDOMNode *prev_node(HTMLTxtRange *This, nsIDOMNode *iter)
00340 {
00341     nsIDOMNode *ret, *tmp;
00342     nsresult nsres;
00343 
00344     if(!iter) {
00345         nsIDOMHTMLElement *nselem;
00346 
00347         nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nselem);
00348         nsIDOMElement_GetLastChild(nselem, &tmp);
00349         if(!tmp)
00350             return (nsIDOMNode*)nselem;
00351 
00352         while(tmp) {
00353             ret = tmp;
00354             nsIDOMNode_GetLastChild(ret, &tmp);
00355         }
00356 
00357         nsIDOMElement_Release(nselem);
00358 
00359         return ret;
00360     }
00361 
00362     nsres = nsIDOMNode_GetLastChild(iter, &ret);
00363     if(NS_SUCCEEDED(nsres) && ret)
00364         return ret;
00365 
00366     nsIDOMNode_AddRef(iter);
00367 
00368     do {
00369         nsres = nsIDOMNode_GetPreviousSibling(iter, &ret);
00370         if(NS_SUCCEEDED(nsres) && ret) {
00371             nsIDOMNode_Release(iter);
00372             return ret;
00373         }
00374 
00375         nsres = nsIDOMNode_GetParentNode(iter, &tmp);
00376         nsIDOMNode_Release(iter);
00377         iter = tmp;
00378     }while(NS_SUCCEEDED(nsres) && iter);
00379 
00380     return NULL;
00381 }
00382 
00383 static nsIDOMNode *get_child_node(nsIDOMNode *node, PRUint32 off)
00384 {
00385     nsIDOMNodeList *node_list;
00386     nsIDOMNode *ret = NULL;
00387 
00388     nsIDOMNode_GetChildNodes(node, &node_list);
00389     nsIDOMNodeList_Item(node_list, off, &ret);
00390     nsIDOMNodeList_Release(node_list);
00391 
00392     return ret;
00393 }
00394 
00395 static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
00396 {
00397     nsIDOMNode *node;
00398     PRInt32 off;
00399 
00400     pos->p = NULL;
00401 
00402     if(!start) {
00403         PRBool collapsed;
00404         nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
00405         start = collapsed;
00406     }
00407 
00408     if(start) {
00409         nsIDOMRange_GetStartContainer(This->nsrange, &node);
00410         nsIDOMRange_GetStartOffset(This->nsrange, &off);
00411     }else {
00412         nsIDOMRange_GetEndContainer(This->nsrange, &node);
00413         nsIDOMRange_GetEndOffset(This->nsrange, &off);
00414     }
00415 
00416     pos->type = get_node_type(node);
00417     if(pos->type == ELEMENT_NODE) {
00418         if(start) {
00419             pos->node = get_child_node(node, off);
00420             pos->off = 0;
00421         }else {
00422             pos->node = off ? get_child_node(node, off-1) : prev_node(This, node);
00423             pos->off = -1;
00424         }
00425 
00426         pos->type = get_node_type(pos->node);
00427         nsIDOMNode_Release(node);
00428     }else if(start) {
00429         pos->node = node;
00430         pos->off = off;
00431     }else if(off) {
00432         pos->node = node;
00433         pos->off = off-1;
00434     }else {
00435         pos->node = prev_node(This, node);
00436         pos->off = -1;
00437         nsIDOMNode_Release(node);
00438     }
00439 
00440     if(pos->type == TEXT_NODE)
00441         fill_nodestr(pos);
00442 }
00443 
00444 static void set_range_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
00445 {
00446     nsresult nsres;
00447 
00448     if(start) {
00449         if(pos->type == TEXT_NODE)
00450             nsres = nsIDOMRange_SetStart(This->nsrange, pos->node, pos->off);
00451         else
00452             nsres = nsIDOMRange_SetStartBefore(This->nsrange, pos->node);
00453     }else {
00454         if(pos->type == TEXT_NODE && pos->p[pos->off+1])
00455             nsres = nsIDOMRange_SetEnd(This->nsrange, pos->node, pos->off+1);
00456         else
00457             nsres = nsIDOMRange_SetEndAfter(This->nsrange, pos->node);
00458     }
00459 
00460     if(NS_FAILED(nsres))
00461         ERR("failed: %p %08x\n", pos->node, nsres);
00462 }
00463 
00464 static inline void dompos_release(dompos_t *pos)
00465 {
00466     if(pos->node)
00467         nsIDOMNode_Release(pos->node);
00468 
00469     if(pos->p)
00470         nsAString_Finish(&pos->str);
00471 }
00472 
00473 static inline void dompos_addref(dompos_t *pos)
00474 {
00475     if(pos->node)
00476         nsIDOMNode_AddRef(pos->node);
00477 
00478     if(pos->type == TEXT_NODE)
00479         fill_nodestr(pos);
00480 }
00481 
00482 static inline BOOL dompos_cmp(const dompos_t *pos1, const dompos_t *pos2)
00483 {
00484     return pos1->node == pos2->node && pos1->off == pos2->off;
00485 }
00486 
00487 static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
00488 {
00489     nsIDOMNode *iter, *tmp;
00490     dompos_t start_pos, end_pos;
00491     PRBool collapsed;
00492 
00493     nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
00494     if(collapsed) {
00495         wstrbuf_finish(buf);
00496         buf->buf = NULL;
00497         buf->size = 0;
00498         return;
00499     }
00500 
00501     get_cur_pos(This, FALSE, &end_pos);
00502     get_cur_pos(This, TRUE, &start_pos);
00503 
00504     if(start_pos.type == TEXT_NODE) {
00505         if(start_pos.node == end_pos.node) {
00506             wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, end_pos.off-start_pos.off+1);
00507             iter = start_pos.node;
00508             nsIDOMNode_AddRef(iter);
00509         }else {
00510             wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, strlenW(start_pos.p+start_pos.off));
00511             iter = next_node(start_pos.node);
00512         }
00513     }else {
00514         iter = start_pos.node;
00515         nsIDOMNode_AddRef(iter);
00516     }
00517 
00518     while(iter != end_pos.node) {
00519         wstrbuf_append_node(buf, iter);
00520         tmp = next_node(iter);
00521         nsIDOMNode_Release(iter);
00522         iter = tmp;
00523     }
00524 
00525     nsIDOMNode_AddRef(end_pos.node);
00526 
00527     if(start_pos.node != end_pos.node) {
00528         if(end_pos.type == TEXT_NODE)
00529             wstrbuf_append_nodetxt(buf, end_pos.p, end_pos.off+1);
00530         else
00531             wstrbuf_append_node(buf, end_pos.node);
00532     }
00533 
00534     nsIDOMNode_Release(iter);
00535     dompos_release(&start_pos);
00536     dompos_release(&end_pos);
00537 
00538     if(buf->len) {
00539         WCHAR *p;
00540 
00541         for(p = buf->buf+buf->len-1; p >= buf->buf && isspaceW(*p); p--);
00542 
00543         p = strchrW(p, '\r');
00544         if(p)
00545             *p = 0;
00546     }
00547 }
00548 
00549 HRESULT get_node_text(HTMLDOMNode *node, BSTR *ret)
00550 {
00551     wstrbuf_t buf;
00552     HRESULT hres = S_OK;
00553 
00554     if (!wstrbuf_init(&buf))
00555         return E_OUTOFMEMORY;
00556     wstrbuf_append_node_rec(&buf, node->nsnode);
00557     if(buf.buf) {
00558         *ret = SysAllocString(buf.buf);
00559         if(!*ret)
00560             hres = E_OUTOFMEMORY;
00561     } else {
00562         *ret = NULL;
00563     }
00564     wstrbuf_finish(&buf);
00565 
00566     if(SUCCEEDED(hres))
00567         TRACE("ret %s\n", debugstr_w(*ret));
00568     return hres;
00569 }
00570 
00571 static WCHAR get_pos_char(const dompos_t *pos)
00572 {
00573     switch(pos->type) {
00574     case TEXT_NODE:
00575         return pos->p[pos->off];
00576     case ELEMENT_NODE:
00577         if(is_space_elem(pos->node))
00578             return '\n';
00579     }
00580 
00581     return 0;
00582 }
00583 
00584 static void end_space(const dompos_t *pos, dompos_t *new_pos)
00585 {
00586     const WCHAR *p;
00587 
00588     *new_pos = *pos;
00589     dompos_addref(new_pos);
00590 
00591     if(pos->type != TEXT_NODE)
00592         return;
00593 
00594     p = new_pos->p+new_pos->off;
00595 
00596     if(!*p || !isspace(*p))
00597         return;
00598 
00599     while(p[1] && isspace(p[1]))
00600         p++;
00601 
00602     new_pos->off = p - new_pos->p;
00603 }
00604 
00605 static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos)
00606 {
00607     nsIDOMNode *iter, *tmp;
00608     dompos_t last_space, tmp_pos;
00609     const WCHAR *p;
00610     WCHAR cspace = 0;
00611 
00612     if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off]) {
00613         p = pos->p+pos->off;
00614 
00615         if(isspace(*p))
00616             while(isspaceW(*++p));
00617         else
00618             p++;
00619 
00620         if(*p && isspaceW(*p)) {
00621             cspace = ' ';
00622             while(p[1] && isspaceW(p[1]))
00623                 p++;
00624         }
00625 
00626         if(*p) {
00627             *new_pos = *pos;
00628             new_pos->off = p - pos->p;
00629             dompos_addref(new_pos);
00630 
00631             return cspace ? cspace : *p;
00632         }else {
00633             last_space = *pos;
00634             last_space.off = p - pos->p;
00635             dompos_addref(&last_space);
00636         }
00637     }
00638 
00639     iter = next_node(pos->node);
00640 
00641     while(iter) {
00642         switch(get_node_type(iter)) {
00643         case TEXT_NODE:
00644             tmp_pos.node = iter;
00645             tmp_pos.type = TEXT_NODE;
00646             tmp_pos.off = 0;
00647             dompos_addref(&tmp_pos);
00648 
00649             p = tmp_pos.p;
00650 
00651             if(!*p) {
00652                 dompos_release(&tmp_pos);
00653                 break;
00654             }else if(isspaceW(*p)) {
00655                 if(cspace)
00656                     dompos_release(&last_space);
00657                 else
00658                     cspace = ' ';
00659 
00660                 while(p[1] && isspaceW(p[1]))
00661                       p++;
00662 
00663                 tmp_pos.off = p-tmp_pos.p;
00664 
00665                 if(!p[1]) {
00666                     last_space = tmp_pos;
00667                     break;
00668                 }
00669 
00670                 *new_pos = tmp_pos;
00671                 nsIDOMNode_Release(iter);
00672                 return cspace;
00673             }else if(cspace) {
00674                 *new_pos = last_space;
00675                 dompos_release(&tmp_pos);
00676                 nsIDOMNode_Release(iter);
00677 
00678                 return cspace;
00679             }else if(*p) {
00680                 tmp_pos.off = 0;
00681                 *new_pos = tmp_pos;
00682             }
00683 
00684             nsIDOMNode_Release(iter);
00685             return *p;
00686 
00687         case ELEMENT_NODE:
00688             if(is_elem_tag(iter, brW)) {
00689                 if(cspace)
00690                     dompos_release(&last_space);
00691                 cspace = '\n';
00692 
00693                 nsIDOMNode_AddRef(iter);
00694                 last_space.node = iter;
00695                 last_space.type = ELEMENT_NODE;
00696                 last_space.off = 0;
00697                 last_space.p = NULL;
00698             }else if(is_elem_tag(iter, hrW)) {
00699                 if(cspace) {
00700                     *new_pos = last_space;
00701                     nsIDOMNode_Release(iter);
00702                     return cspace;
00703                 }
00704 
00705                 new_pos->node = iter;
00706                 new_pos->type = ELEMENT_NODE;
00707                 new_pos->off = 0;
00708                 new_pos->p = NULL;
00709                 return '\n';
00710             }
00711         }
00712 
00713         tmp = iter;
00714         iter = next_node(iter);
00715         nsIDOMNode_Release(tmp);
00716     }
00717 
00718     if(cspace) {
00719         *new_pos = last_space;
00720     }else {
00721         *new_pos = *pos;
00722         dompos_addref(new_pos);
00723     }
00724 
00725     return cspace;
00726 }
00727 
00728 static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos)
00729 {
00730     nsIDOMNode *iter, *tmp;
00731     const WCHAR *p;
00732     BOOL skip_space = FALSE;
00733 
00734     if(pos->type == TEXT_NODE && isspaceW(pos->p[pos->off]))
00735         skip_space = TRUE;
00736 
00737     if(pos->type == TEXT_NODE && pos->off) {
00738         p = pos->p+pos->off-1;
00739 
00740         if(skip_space) {
00741             while(p >= pos->p && isspace(*p))
00742                 p--;
00743         }
00744 
00745         if(p >= pos->p) {
00746             *new_pos = *pos;
00747             new_pos->off = p-pos->p;
00748             dompos_addref(new_pos);
00749             return new_pos->p[new_pos->off];
00750         }
00751     }
00752 
00753     iter = prev_node(This, pos->node);
00754 
00755     while(iter) {
00756         switch(get_node_type(iter)) {
00757         case TEXT_NODE: {
00758             dompos_t tmp_pos;
00759 
00760             tmp_pos.node = iter;
00761             tmp_pos.type = TEXT_NODE;
00762             tmp_pos.off = 0;
00763             dompos_addref(&tmp_pos);
00764 
00765             p = tmp_pos.p + strlenW(tmp_pos.p)-1;
00766 
00767             if(skip_space) {
00768                 while(p >= tmp_pos.p && isspaceW(*p))
00769                     p--;
00770             }
00771 
00772             if(p < tmp_pos.p) {
00773                 dompos_release(&tmp_pos);
00774                 break;
00775             }
00776 
00777             tmp_pos.off = p-tmp_pos.p;
00778             *new_pos = tmp_pos;
00779             nsIDOMNode_Release(iter);
00780             return *p;
00781         }
00782 
00783         case ELEMENT_NODE:
00784             if(is_elem_tag(iter, brW)) {
00785                 if(skip_space) {
00786                     skip_space = FALSE;
00787                     break;
00788                 }
00789             }else if(!is_elem_tag(iter, hrW)) {
00790                 break;
00791             }
00792 
00793             new_pos->node = iter;
00794             new_pos->type = ELEMENT_NODE;
00795             new_pos->off = 0;
00796             new_pos->p = NULL;
00797             return '\n';
00798         }
00799 
00800         tmp = iter;
00801         iter = prev_node(This, iter);
00802         nsIDOMNode_Release(tmp);
00803     }
00804 
00805     *new_pos = *pos;
00806     dompos_addref(new_pos);
00807     return 0;
00808 }
00809 
00810 static LONG move_next_chars(LONG cnt, const dompos_t *pos, BOOL col, const dompos_t *bound_pos,
00811         BOOL *bounded, dompos_t *new_pos)
00812 {
00813     dompos_t iter, tmp;
00814     LONG ret = 0;
00815     WCHAR c;
00816 
00817     if(bounded)
00818         *bounded = FALSE;
00819 
00820     if(col)
00821         ret++;
00822 
00823     if(ret >= cnt) {
00824         end_space(pos, new_pos);
00825         return ret;
00826     }
00827 
00828     c = next_char(pos, &iter);
00829     ret++;
00830 
00831     while(ret < cnt) {
00832         tmp = iter;
00833         c = next_char(&tmp, &iter);
00834         dompos_release(&tmp);
00835         if(!c)
00836             break;
00837 
00838         ret++;
00839         if(bound_pos && dompos_cmp(&tmp, bound_pos)) {
00840             *bounded = TRUE;
00841             ret++;
00842         }
00843     }
00844 
00845     *new_pos = iter;
00846     return ret;
00847 }
00848 
00849 static LONG move_prev_chars(HTMLTxtRange *This, LONG cnt, const dompos_t *pos, BOOL end,
00850         const dompos_t *bound_pos, BOOL *bounded, dompos_t *new_pos)
00851 {
00852     dompos_t iter, tmp;
00853     LONG ret = 0;
00854     BOOL prev_eq = FALSE;
00855     WCHAR c;
00856 
00857     if(bounded)
00858         *bounded = FALSE;
00859 
00860     c = prev_char(This, pos, &iter);
00861     if(c)
00862         ret++;
00863 
00864     while(c && ret < cnt) {
00865         tmp = iter;
00866         c = prev_char(This, &tmp, &iter);
00867         dompos_release(&tmp);
00868         if(!c) {
00869             if(end)
00870                 ret++;
00871             break;
00872         }
00873 
00874         ret++;
00875 
00876         if(prev_eq) {
00877             *bounded = TRUE;
00878             ret++;
00879         }
00880 
00881         prev_eq = bound_pos && dompos_cmp(&iter, bound_pos);
00882     }
00883 
00884     *new_pos = iter;
00885     return ret;
00886 }
00887 
00888 static LONG find_prev_space(HTMLTxtRange *This, const dompos_t *pos, BOOL first_space, dompos_t *ret)
00889 {
00890     dompos_t iter, tmp;
00891     WCHAR c;
00892 
00893     c = prev_char(This, pos, &iter);
00894     if(!c || (first_space && isspaceW(c))) {
00895         *ret = iter;
00896         return FALSE;
00897     }
00898 
00899     while(1) {
00900         tmp = iter;
00901         c = prev_char(This, &tmp, &iter);
00902         if(!c || isspaceW(c)) {
00903             dompos_release(&iter);
00904             break;
00905         }
00906         dompos_release(&tmp);
00907     }
00908 
00909     *ret = tmp;
00910     return TRUE;
00911 }
00912 
00913 static int find_word_end(const dompos_t *pos, dompos_t *ret)
00914 {
00915     dompos_t iter, tmp;
00916     int cnt = 1;
00917     WCHAR c;
00918     c = get_pos_char(pos);
00919     if(isspaceW(c)) {
00920         *ret = *pos;
00921         dompos_addref(ret);
00922         return 0;
00923     }
00924 
00925     c = next_char(pos, &iter);
00926     if(!c) {
00927         *ret = iter;
00928         return 0;
00929     }
00930     if(c == '\n') {
00931         *ret = *pos;
00932         dompos_addref(ret);
00933         return 0;
00934     }
00935 
00936     while(c && !isspaceW(c)) {
00937         tmp = iter;
00938         c = next_char(&tmp, &iter);
00939         if(c == '\n') {
00940             dompos_release(&iter);
00941             iter = tmp;
00942         }else {
00943             cnt++;
00944             dompos_release(&tmp);
00945         }
00946     }
00947 
00948     *ret = iter;
00949     return cnt;
00950 }
00951 
00952 static LONG move_next_words(LONG cnt, const dompos_t *pos, dompos_t *new_pos)
00953 {
00954     dompos_t iter, tmp;
00955     LONG ret = 0;
00956     WCHAR c;
00957 
00958     c = get_pos_char(pos);
00959     if(isspaceW(c)) {
00960         end_space(pos, &iter);
00961         ret++;
00962     }else {
00963         c = next_char(pos, &iter);
00964         if(c && isspaceW(c))
00965             ret++;
00966     }
00967 
00968     while(c && ret < cnt) {
00969         tmp = iter;
00970         c = next_char(&tmp, &iter);
00971         dompos_release(&tmp);
00972         if(isspaceW(c))
00973             ret++;
00974     }
00975 
00976     *new_pos = iter;
00977     return ret;
00978 }
00979 
00980 static LONG move_prev_words(HTMLTxtRange *This, LONG cnt, const dompos_t *pos, dompos_t *new_pos)
00981 {
00982     dompos_t iter, tmp;
00983     LONG ret = 0;
00984 
00985     iter = *pos;
00986     dompos_addref(&iter);
00987 
00988     while(ret < cnt) {
00989         if(!find_prev_space(This, &iter, FALSE, &tmp))
00990             break;
00991 
00992         dompos_release(&iter);
00993         iter = tmp;
00994         ret++;
00995     }
00996 
00997     *new_pos = iter;
00998     return ret;
00999 }
01000 
01001 #define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface)
01002 
01003 static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv)
01004 {
01005     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01006 
01007     *ppv = NULL;
01008 
01009     if(IsEqualGUID(&IID_IUnknown, riid)) {
01010         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
01011         *ppv = HTMLTXTRANGE(This);
01012     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
01013         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
01014         *ppv = HTMLTXTRANGE(This);
01015     }else if(IsEqualGUID(&IID_IHTMLTxtRange, riid)) {
01016         TRACE("(%p)->(IID_IHTMLTxtRange %p)\n", This, ppv);
01017         *ppv = HTMLTXTRANGE(This);
01018     }else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) {
01019         TRACE("(%p)->(IID_IOleCommandTarget %p)\n", This, ppv);
01020         *ppv = CMDTARGET(This);
01021     }
01022 
01023     if(*ppv) {
01024         IUnknown_AddRef((IUnknown*)*ppv);
01025         return S_OK;
01026     }
01027 
01028     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
01029     return E_NOINTERFACE;
01030 }
01031 
01032 static ULONG WINAPI HTMLTxtRange_AddRef(IHTMLTxtRange *iface)
01033 {
01034     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01035     LONG ref = InterlockedIncrement(&This->ref);
01036 
01037     TRACE("(%p) ref=%d\n", This, ref);
01038 
01039     return ref;
01040 }
01041 
01042 static ULONG WINAPI HTMLTxtRange_Release(IHTMLTxtRange *iface)
01043 {
01044     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01045     LONG ref = InterlockedDecrement(&This->ref);
01046 
01047     TRACE("(%p) ref=%d\n", This, ref);
01048 
01049     if(!ref) {
01050         if(This->nsrange)
01051             nsISelection_Release(This->nsrange);
01052         if(This->doc)
01053             list_remove(&This->entry);
01054         heap_free(This);
01055     }
01056 
01057     return ref;
01058 }
01059 
01060 static HRESULT WINAPI HTMLTxtRange_GetTypeInfoCount(IHTMLTxtRange *iface, UINT *pctinfo)
01061 {
01062     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01063     FIXME("(%p)->(%p)\n", This, pctinfo);
01064     return E_NOTIMPL;
01065 }
01066 
01067 static HRESULT WINAPI HTMLTxtRange_GetTypeInfo(IHTMLTxtRange *iface, UINT iTInfo,
01068                                                LCID lcid, ITypeInfo **ppTInfo)
01069 {
01070     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01071     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
01072     return E_NOTIMPL;
01073 }
01074 
01075 static HRESULT WINAPI HTMLTxtRange_GetIDsOfNames(IHTMLTxtRange *iface, REFIID riid,
01076                                                  LPOLESTR *rgszNames, UINT cNames,
01077                                                  LCID lcid, DISPID *rgDispId)
01078 {
01079     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01080     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
01081           lcid, rgDispId);
01082     return E_NOTIMPL;
01083 }
01084 
01085 static HRESULT WINAPI HTMLTxtRange_Invoke(IHTMLTxtRange *iface, DISPID dispIdMember,
01086                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
01087                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
01088 {
01089     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01090     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
01091           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
01092     return E_NOTIMPL;
01093 }
01094 
01095 static HRESULT WINAPI HTMLTxtRange_get_htmlText(IHTMLTxtRange *iface, BSTR *p)
01096 {
01097     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01098 
01099     TRACE("(%p)->(%p)\n", This, p);
01100 
01101     *p = NULL;
01102 
01103     if(This->nsrange) {
01104         nsIDOMDocumentFragment *fragment;
01105         nsresult nsres;
01106 
01107         nsres = nsIDOMRange_CloneContents(This->nsrange, &fragment);
01108         if(NS_SUCCEEDED(nsres)) {
01109             const PRUnichar *nstext;
01110             nsAString nsstr;
01111 
01112             nsAString_Init(&nsstr, NULL);
01113             nsnode_to_nsstring((nsIDOMNode*)fragment, &nsstr);
01114             nsIDOMDocumentFragment_Release(fragment);
01115 
01116             nsAString_GetData(&nsstr, &nstext);
01117             *p = SysAllocString(nstext);
01118 
01119             nsAString_Finish(&nsstr);
01120         }
01121     }
01122 
01123     if(!*p) {
01124         const WCHAR emptyW[] = {0};
01125         *p = SysAllocString(emptyW);
01126     }
01127 
01128     TRACE("return %s\n", debugstr_w(*p));
01129     return S_OK;
01130 }
01131 
01132 static HRESULT WINAPI HTMLTxtRange_put_text(IHTMLTxtRange *iface, BSTR v)
01133 {
01134     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01135     nsIDOMText *text_node;
01136     nsAString text_str;
01137     nsresult nsres;
01138 
01139     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
01140 
01141     if(!This->doc)
01142         return MSHTML_E_NODOC;
01143 
01144     nsAString_InitDepend(&text_str, v);
01145     nsres = nsIDOMHTMLDocument_CreateTextNode(This->doc->nsdoc, &text_str, &text_node);
01146     nsAString_Finish(&text_str);
01147     if(NS_FAILED(nsres)) {
01148         ERR("CreateTextNode failed: %08x\n", nsres);
01149         return S_OK;
01150     }
01151     nsres = nsIDOMRange_DeleteContents(This->nsrange);
01152     if(NS_FAILED(nsres))
01153         ERR("DeleteContents failed: %08x\n", nsres);
01154 
01155     nsres = nsIDOMRange_InsertNode(This->nsrange, (nsIDOMNode*)text_node);
01156     if(NS_FAILED(nsres))
01157         ERR("InsertNode failed: %08x\n", nsres);
01158 
01159     nsres = nsIDOMRange_SetEndAfter(This->nsrange, (nsIDOMNode*)text_node);
01160     if(NS_FAILED(nsres))
01161         ERR("SetEndAfter failed: %08x\n", nsres);
01162 
01163     return IHTMLTxtRange_collapse(HTMLTXTRANGE(This), VARIANT_FALSE);
01164 }
01165 
01166 static HRESULT WINAPI HTMLTxtRange_get_text(IHTMLTxtRange *iface, BSTR *p)
01167 {
01168     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01169     wstrbuf_t buf;
01170 
01171     TRACE("(%p)->(%p)\n", This, p);
01172 
01173     *p = NULL;
01174     if(!This->nsrange)
01175         return S_OK;
01176 
01177     if (!wstrbuf_init(&buf))
01178         return E_OUTOFMEMORY;
01179     range_to_string(This, &buf);
01180     if (buf.buf)
01181         *p = SysAllocString(buf.buf);
01182     wstrbuf_finish(&buf);
01183 
01184     TRACE("ret %s\n", debugstr_w(*p));
01185     return S_OK;
01186 }
01187 
01188 static HRESULT WINAPI HTMLTxtRange_parentElement(IHTMLTxtRange *iface, IHTMLElement **parent)
01189 {
01190     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01191     nsIDOMNode *nsnode, *tmp;
01192     HTMLDOMNode *node;
01193 
01194     TRACE("(%p)->(%p)\n", This, parent);
01195 
01196     nsIDOMRange_GetCommonAncestorContainer(This->nsrange, &nsnode);
01197     while(nsnode && get_node_type(nsnode) != ELEMENT_NODE) {
01198         nsIDOMNode_GetParentNode(nsnode, &tmp);
01199         nsIDOMNode_Release(nsnode);
01200         nsnode = tmp;
01201     }
01202 
01203     if(!nsnode) {
01204         *parent = NULL;
01205         return S_OK;
01206     }
01207 
01208     node = get_node(This->doc, nsnode, TRUE);
01209     nsIDOMNode_Release(nsnode);
01210 
01211     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(node), &IID_IHTMLElement, (void**)parent);
01212 }
01213 
01214 static HRESULT WINAPI HTMLTxtRange_duplicate(IHTMLTxtRange *iface, IHTMLTxtRange **Duplicate)
01215 {
01216     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01217     nsIDOMRange *nsrange = NULL;
01218     HRESULT hres;
01219 
01220     TRACE("(%p)->(%p)\n", This, Duplicate);
01221 
01222     nsIDOMRange_CloneRange(This->nsrange, &nsrange);
01223     hres = HTMLTxtRange_Create(This->doc, nsrange, Duplicate);
01224     nsIDOMRange_Release(nsrange);
01225 
01226     return hres;
01227 }
01228 
01229 static HRESULT WINAPI HTMLTxtRange_inRange(IHTMLTxtRange *iface, IHTMLTxtRange *Range,
01230         VARIANT_BOOL *InRange)
01231 {
01232     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01233     HTMLTxtRange *src_range;
01234     PRInt16 nsret = 0;
01235     nsresult nsres;
01236 
01237     TRACE("(%p)->(%p %p)\n", This, Range, InRange);
01238 
01239     *InRange = VARIANT_FALSE;
01240 
01241     src_range = get_range_object(This->doc, Range);
01242     if(!src_range)
01243         return E_FAIL;
01244 
01245     nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_START_TO_START,
01246             src_range->nsrange, &nsret);
01247     if(NS_SUCCEEDED(nsres) && nsret <= 0) {
01248         nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_END_TO_END,
01249                 src_range->nsrange, &nsret);
01250         if(NS_SUCCEEDED(nsres) && nsret >= 0)
01251             *InRange = VARIANT_TRUE;
01252     }
01253 
01254     if(NS_FAILED(nsres))
01255         ERR("CompareBoundaryPoints failed: %08x\n", nsres);
01256 
01257     return S_OK;
01258 }
01259 
01260 static HRESULT WINAPI HTMLTxtRange_isEqual(IHTMLTxtRange *iface, IHTMLTxtRange *Range,
01261         VARIANT_BOOL *IsEqual)
01262 {
01263     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01264     HTMLTxtRange *src_range;
01265     PRInt16 nsret = 0;
01266     nsresult nsres;
01267 
01268     TRACE("(%p)->(%p %p)\n", This, Range, IsEqual);
01269 
01270     *IsEqual = VARIANT_FALSE;
01271 
01272     src_range = get_range_object(This->doc, Range);
01273     if(!src_range)
01274         return E_FAIL;
01275 
01276     nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_START_TO_START,
01277             src_range->nsrange, &nsret);
01278     if(NS_SUCCEEDED(nsres) && !nsret) {
01279         nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_END_TO_END,
01280                 src_range->nsrange, &nsret);
01281         if(NS_SUCCEEDED(nsres) && !nsret)
01282             *IsEqual = VARIANT_TRUE;
01283     }
01284 
01285     if(NS_FAILED(nsres))
01286         ERR("CompareBoundaryPoints failed: %08x\n", nsres);
01287 
01288     return S_OK;
01289 }
01290 
01291 static HRESULT WINAPI HTMLTxtRange_scrollIntoView(IHTMLTxtRange *iface, VARIANT_BOOL fStart)
01292 {
01293     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01294     FIXME("(%p)->(%x)\n", This, fStart);
01295     return E_NOTIMPL;
01296 }
01297 
01298 static HRESULT WINAPI HTMLTxtRange_collapse(IHTMLTxtRange *iface, VARIANT_BOOL Start)
01299 {
01300     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01301 
01302     TRACE("(%p)->(%x)\n", This, Start);
01303 
01304     nsIDOMRange_Collapse(This->nsrange, Start != VARIANT_FALSE);
01305     return S_OK;
01306 }
01307 
01308 static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIANT_BOOL *Success)
01309 {
01310     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01311     range_unit_t unit;
01312 
01313     TRACE("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success);
01314 
01315     unit = string_to_unit(Unit);
01316     if(unit == RU_UNKNOWN)
01317         return E_INVALIDARG;
01318 
01319     *Success = VARIANT_FALSE;
01320 
01321     switch(unit) {
01322     case RU_WORD: {
01323         dompos_t end_pos, start_pos, new_start_pos, new_end_pos;
01324         PRBool collapsed;
01325 
01326         nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
01327 
01328         get_cur_pos(This, TRUE, &start_pos);
01329         get_cur_pos(This, FALSE, &end_pos);
01330 
01331         if(find_word_end(&end_pos, &new_end_pos) || collapsed) {
01332             set_range_pos(This, FALSE, &new_end_pos);
01333             *Success = VARIANT_TRUE;
01334         }
01335 
01336         if(start_pos.type && (get_pos_char(&end_pos) || !dompos_cmp(&new_end_pos, &end_pos))) {
01337             if(find_prev_space(This, &start_pos, TRUE, &new_start_pos)) {
01338                 set_range_pos(This, TRUE, &new_start_pos);
01339                 *Success = VARIANT_TRUE;
01340             }
01341             dompos_release(&new_start_pos);
01342         }
01343 
01344         dompos_release(&new_end_pos);
01345         dompos_release(&end_pos);
01346         dompos_release(&start_pos);
01347 
01348         break;
01349     }
01350 
01351     case RU_TEXTEDIT: {
01352         nsIDOMHTMLElement *nsbody = NULL;
01353         nsresult nsres;
01354 
01355         nsres = nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nsbody);
01356         if(NS_FAILED(nsres) || !nsbody) {
01357             ERR("Could not get body: %08x\n", nsres);
01358             break;
01359         }
01360 
01361         nsres = nsIDOMRange_SelectNodeContents(This->nsrange, (nsIDOMNode*)nsbody);
01362         nsIDOMHTMLElement_Release(nsbody);
01363         if(NS_FAILED(nsres)) {
01364             ERR("Collapse failed: %08x\n", nsres);
01365             break;
01366         }
01367 
01368         *Success = VARIANT_TRUE;
01369         break;
01370     }
01371 
01372     default:
01373         FIXME("Unimplemented unit %s\n", debugstr_w(Unit));
01374     }
01375 
01376     return S_OK;
01377 }
01378 
01379 static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit,
01380         LONG Count, LONG *ActualCount)
01381 {
01382     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01383     range_unit_t unit;
01384 
01385     TRACE("(%p)->(%s %d %p)\n", This, debugstr_w(Unit), Count, ActualCount);
01386 
01387     unit = string_to_unit(Unit);
01388     if(unit == RU_UNKNOWN)
01389         return E_INVALIDARG;
01390 
01391     if(!Count) {
01392         *ActualCount = 0;
01393         return IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
01394     }
01395 
01396     switch(unit) {
01397     case RU_CHAR: {
01398         dompos_t cur_pos, new_pos;
01399 
01400         get_cur_pos(This, TRUE, &cur_pos);
01401 
01402         if(Count > 0) {
01403             *ActualCount = move_next_chars(Count, &cur_pos, TRUE, NULL, NULL, &new_pos);
01404             set_range_pos(This, FALSE, &new_pos);
01405             dompos_release(&new_pos);
01406 
01407             IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE);
01408         }else {
01409             *ActualCount = -move_prev_chars(This, -Count, &cur_pos, FALSE, NULL, NULL, &new_pos);
01410             set_range_pos(This, TRUE, &new_pos);
01411             IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
01412             dompos_release(&new_pos);
01413         }
01414 
01415         dompos_release(&cur_pos);
01416         break;
01417     }
01418 
01419     case RU_WORD: {
01420         dompos_t cur_pos, new_pos;
01421 
01422         get_cur_pos(This, TRUE, &cur_pos);
01423 
01424         if(Count > 0) {
01425             *ActualCount = move_next_words(Count, &cur_pos, &new_pos);
01426             set_range_pos(This, FALSE, &new_pos);
01427             dompos_release(&new_pos);
01428             IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE);
01429         }else {
01430             *ActualCount = -move_prev_words(This, -Count, &cur_pos, &new_pos);
01431             set_range_pos(This, TRUE, &new_pos);
01432             IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
01433             dompos_release(&new_pos);
01434         }
01435 
01436         dompos_release(&cur_pos);
01437         break;
01438     }
01439 
01440     default:
01441         FIXME("unimplemented unit %s\n", debugstr_w(Unit));
01442     }
01443 
01444     TRACE("ret %d\n", *ActualCount);
01445     return S_OK;
01446 }
01447 
01448 static HRESULT WINAPI HTMLTxtRange_moveStart(IHTMLTxtRange *iface, BSTR Unit,
01449         LONG Count, LONG *ActualCount)
01450 {
01451     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01452     range_unit_t unit;
01453 
01454     TRACE("(%p)->(%s %d %p)\n", This, debugstr_w(Unit), Count, ActualCount);
01455 
01456     unit = string_to_unit(Unit);
01457     if(unit == RU_UNKNOWN)
01458         return E_INVALIDARG;
01459 
01460     if(!Count) {
01461         *ActualCount = 0;
01462         return S_OK;
01463     }
01464 
01465     switch(unit) {
01466     case RU_CHAR: {
01467         dompos_t start_pos, end_pos, new_pos;
01468         PRBool collapsed;
01469 
01470         get_cur_pos(This, TRUE, &start_pos);
01471         get_cur_pos(This, FALSE, &end_pos);
01472         nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
01473 
01474         if(Count > 0) {
01475             BOOL bounded;
01476 
01477             *ActualCount = move_next_chars(Count, &start_pos, collapsed, &end_pos, &bounded, &new_pos);
01478             set_range_pos(This, !bounded, &new_pos);
01479             if(bounded)
01480                 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE);
01481         }else {
01482             *ActualCount = -move_prev_chars(This, -Count, &start_pos, FALSE, NULL, NULL, &new_pos);
01483             set_range_pos(This, TRUE, &new_pos);
01484         }
01485 
01486         dompos_release(&start_pos);
01487         dompos_release(&end_pos);
01488         dompos_release(&new_pos);
01489         break;
01490     }
01491 
01492     default:
01493         FIXME("unimplemented unit %s\n", debugstr_w(Unit));
01494     }
01495 
01496     return S_OK;
01497 }
01498 
01499 static HRESULT WINAPI HTMLTxtRange_moveEnd(IHTMLTxtRange *iface, BSTR Unit,
01500         LONG Count, LONG *ActualCount)
01501 {
01502     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01503     range_unit_t unit;
01504 
01505     TRACE("(%p)->(%s %d %p)\n", This, debugstr_w(Unit), Count, ActualCount);
01506 
01507     unit = string_to_unit(Unit);
01508     if(unit == RU_UNKNOWN)
01509         return E_INVALIDARG;
01510 
01511     if(!Count) {
01512         *ActualCount = 0;
01513         return S_OK;
01514     }
01515 
01516     switch(unit) {
01517     case RU_CHAR: {
01518         dompos_t start_pos, end_pos, new_pos;
01519         PRBool collapsed;
01520 
01521         get_cur_pos(This, TRUE, &start_pos);
01522         get_cur_pos(This, FALSE, &end_pos);
01523         nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
01524 
01525         if(Count > 0) {
01526             *ActualCount = move_next_chars(Count, &end_pos, collapsed, NULL, NULL, &new_pos);
01527             set_range_pos(This, FALSE, &new_pos);
01528         }else {
01529             BOOL bounded;
01530 
01531             *ActualCount = -move_prev_chars(This, -Count, &end_pos, TRUE, &start_pos, &bounded, &new_pos);
01532             set_range_pos(This, bounded, &new_pos);
01533             if(bounded)
01534                 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
01535         }
01536 
01537         dompos_release(&start_pos);
01538         dompos_release(&end_pos);
01539         dompos_release(&new_pos);
01540         break;
01541     }
01542 
01543     default:
01544         FIXME("unimplemented unit %s\n", debugstr_w(Unit));
01545     }
01546 
01547     return S_OK;
01548 }
01549 
01550 static HRESULT WINAPI HTMLTxtRange_select(IHTMLTxtRange *iface)
01551 {
01552     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01553     nsISelection *nsselection;
01554     nsresult nsres;
01555 
01556     TRACE("(%p)\n", This);
01557 
01558     nsres = nsIDOMWindow_GetSelection(This->doc->basedoc.window->nswindow, &nsselection);
01559     if(NS_FAILED(nsres)) {
01560         ERR("GetSelection failed: %08x\n", nsres);
01561         return E_FAIL;
01562     }
01563 
01564     nsISelection_RemoveAllRanges(nsselection);
01565     nsISelection_AddRange(nsselection, This->nsrange);
01566     nsISelection_Release(nsselection);
01567     return S_OK;
01568 }
01569 
01570 static HRESULT WINAPI HTMLTxtRange_pasteHTML(IHTMLTxtRange *iface, BSTR html)
01571 {
01572     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01573     FIXME("(%p)->(%s)\n", This, debugstr_w(html));
01574     return E_NOTIMPL;
01575 }
01576 
01577 static HRESULT WINAPI HTMLTxtRange_moveToElementText(IHTMLTxtRange *iface, IHTMLElement *element)
01578 {
01579     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01580     FIXME("(%p)->(%p)\n", This, element);
01581     return E_NOTIMPL;
01582 }
01583 
01584 static HRESULT WINAPI HTMLTxtRange_setEndPoint(IHTMLTxtRange *iface, BSTR how,
01585         IHTMLTxtRange *SourceRange)
01586 {
01587     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01588     FIXME("(%p)->(%s %p)\n", This, debugstr_w(how), SourceRange);
01589     return E_NOTIMPL;
01590 }
01591 
01592 static HRESULT WINAPI HTMLTxtRange_compareEndPoints(IHTMLTxtRange *iface, BSTR how,
01593         IHTMLTxtRange *SourceRange, LONG *ret)
01594 {
01595     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01596     HTMLTxtRange *src_range;
01597     PRInt16 nsret = 0;
01598     int nscmpt;
01599     nsresult nsres;
01600 
01601     TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(how), SourceRange, ret);
01602 
01603     nscmpt = string_to_nscmptype(how);
01604     if(nscmpt == -1)
01605         return E_INVALIDARG;
01606 
01607     src_range = get_range_object(This->doc, SourceRange);
01608     if(!src_range)
01609         return E_FAIL;
01610 
01611     nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, nscmpt, src_range->nsrange, &nsret);
01612     if(NS_FAILED(nsres))
01613         ERR("CompareBoundaryPoints failed: %08x\n", nsres);
01614 
01615     *ret = nsret;
01616     return S_OK;
01617 }
01618 
01619 static HRESULT WINAPI HTMLTxtRange_findText(IHTMLTxtRange *iface, BSTR String,
01620         LONG count, LONG Flags, VARIANT_BOOL *Success)
01621 {
01622     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01623     FIXME("(%p)->(%s %d %08x %p)\n", This, debugstr_w(String), count, Flags, Success);
01624     return E_NOTIMPL;
01625 }
01626 
01627 static HRESULT WINAPI HTMLTxtRange_moveToPoint(IHTMLTxtRange *iface, LONG x, LONG y)
01628 {
01629     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01630     FIXME("(%p)->(%d %d)\n", This, x, y);
01631     return E_NOTIMPL;
01632 }
01633 
01634 static HRESULT WINAPI HTMLTxtRange_getBookmark(IHTMLTxtRange *iface, BSTR *Bookmark)
01635 {
01636     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01637     FIXME("(%p)->(%p)\n", This, Bookmark);
01638     return E_NOTIMPL;
01639 }
01640 
01641 static HRESULT WINAPI HTMLTxtRange_moveToBookmark(IHTMLTxtRange *iface, BSTR Bookmark,
01642         VARIANT_BOOL *Success)
01643 {
01644     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01645     FIXME("(%p)->(%s %p)\n", This, debugstr_w(Bookmark), Success);
01646     return E_NOTIMPL;
01647 }
01648 
01649 static HRESULT WINAPI HTMLTxtRange_queryCommandSupported(IHTMLTxtRange *iface, BSTR cmdID,
01650         VARIANT_BOOL *pfRet)
01651 {
01652     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01653     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
01654     return E_NOTIMPL;
01655 }
01656 
01657 static HRESULT WINAPI HTMLTxtRange_queryCommandEnabled(IHTMLTxtRange *iface, BSTR cmdID,
01658         VARIANT_BOOL *pfRet)
01659 {
01660     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01661     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
01662     return E_NOTIMPL;
01663 }
01664 
01665 static HRESULT WINAPI HTMLTxtRange_queryCommandState(IHTMLTxtRange *iface, BSTR cmdID,
01666         VARIANT_BOOL *pfRet)
01667 {
01668     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01669     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
01670     return E_NOTIMPL;
01671 }
01672 
01673 static HRESULT WINAPI HTMLTxtRange_queryCommandIndeterm(IHTMLTxtRange *iface, BSTR cmdID,
01674         VARIANT_BOOL *pfRet)
01675 {
01676     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01677     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
01678     return E_NOTIMPL;
01679 }
01680 
01681 static HRESULT WINAPI HTMLTxtRange_queryCommandText(IHTMLTxtRange *iface, BSTR cmdID,
01682         BSTR *pcmdText)
01683 {
01684     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01685     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdText);
01686     return E_NOTIMPL;
01687 }
01688 
01689 static HRESULT WINAPI HTMLTxtRange_queryCommandValue(IHTMLTxtRange *iface, BSTR cmdID,
01690         VARIANT *pcmdValue)
01691 {
01692     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01693     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdValue);
01694     return E_NOTIMPL;
01695 }
01696 
01697 static HRESULT WINAPI HTMLTxtRange_execCommand(IHTMLTxtRange *iface, BSTR cmdID,
01698         VARIANT_BOOL showUI, VARIANT value, VARIANT_BOOL *pfRet)
01699 {
01700     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01701     FIXME("(%p)->(%s %x v %p)\n", This, debugstr_w(cmdID), showUI, pfRet);
01702     return E_NOTIMPL;
01703 }
01704 
01705 static HRESULT WINAPI HTMLTxtRange_execCommandShowHelp(IHTMLTxtRange *iface, BSTR cmdID,
01706         VARIANT_BOOL *pfRet)
01707 {
01708     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
01709     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
01710     return E_NOTIMPL;
01711 }
01712 
01713 #undef HTMLTXTRANGE_THIS
01714 
01715 static const IHTMLTxtRangeVtbl HTMLTxtRangeVtbl = {
01716     HTMLTxtRange_QueryInterface,
01717     HTMLTxtRange_AddRef,
01718     HTMLTxtRange_Release,
01719     HTMLTxtRange_GetTypeInfoCount,
01720     HTMLTxtRange_GetTypeInfo,
01721     HTMLTxtRange_GetIDsOfNames,
01722     HTMLTxtRange_Invoke,
01723     HTMLTxtRange_get_htmlText,
01724     HTMLTxtRange_put_text,
01725     HTMLTxtRange_get_text,
01726     HTMLTxtRange_parentElement,
01727     HTMLTxtRange_duplicate,
01728     HTMLTxtRange_inRange,
01729     HTMLTxtRange_isEqual,
01730     HTMLTxtRange_scrollIntoView,
01731     HTMLTxtRange_collapse,
01732     HTMLTxtRange_expand,
01733     HTMLTxtRange_move,
01734     HTMLTxtRange_moveStart,
01735     HTMLTxtRange_moveEnd,
01736     HTMLTxtRange_select,
01737     HTMLTxtRange_pasteHTML,
01738     HTMLTxtRange_moveToElementText,
01739     HTMLTxtRange_setEndPoint,
01740     HTMLTxtRange_compareEndPoints,
01741     HTMLTxtRange_findText,
01742     HTMLTxtRange_moveToPoint,
01743     HTMLTxtRange_getBookmark,
01744     HTMLTxtRange_moveToBookmark,
01745     HTMLTxtRange_queryCommandSupported,
01746     HTMLTxtRange_queryCommandEnabled,
01747     HTMLTxtRange_queryCommandState,
01748     HTMLTxtRange_queryCommandIndeterm,
01749     HTMLTxtRange_queryCommandText,
01750     HTMLTxtRange_queryCommandValue,
01751     HTMLTxtRange_execCommand,
01752     HTMLTxtRange_execCommandShowHelp
01753 };
01754 
01755 #define OLECMDTRG_THIS(iface) DEFINE_THIS(HTMLTxtRange, OleCommandTarget, iface)
01756 
01757 static HRESULT WINAPI RangeCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
01758 {
01759     HTMLTxtRange *This = OLECMDTRG_THIS(iface);
01760     return IHTMLTxtRange_QueryInterface(HTMLTXTRANGE(This), riid, ppv);
01761 }
01762 
01763 static ULONG WINAPI RangeCommandTarget_AddRef(IOleCommandTarget *iface)
01764 {
01765     HTMLTxtRange *This = OLECMDTRG_THIS(iface);
01766     return IHTMLTxtRange_AddRef(HTMLTXTRANGE(This));
01767 }
01768 
01769 static ULONG WINAPI RangeCommandTarget_Release(IOleCommandTarget *iface)
01770 {
01771     HTMLTxtRange *This = OLECMDTRG_THIS(iface);
01772     return IHTMLTxtRange_Release(HTMLTXTRANGE(This));
01773 }
01774 
01775 static HRESULT WINAPI RangeCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
01776         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
01777 {
01778     HTMLTxtRange *This = OLECMDTRG_THIS(iface);
01779     FIXME("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
01780     return E_NOTIMPL;
01781 }
01782 
01783 static HRESULT exec_indent(HTMLTxtRange *This, VARIANT *in, VARIANT *out)
01784 {
01785     nsIDOMHTMLElement *blockquote_elem, *p_elem;
01786     nsIDOMDocumentFragment *fragment;
01787     nsIDOMNode *tmp;
01788 
01789     static const PRUnichar blockquoteW[] = {'B','L','O','C','K','Q','U','O','T','E',0};
01790     static const PRUnichar pW[] = {'P',0};
01791 
01792     TRACE("(%p)->(%p %p)\n", This, in, out);
01793 
01794     if(!This->doc->nsdoc) {
01795         WARN("NULL nsdoc\n");
01796         return E_NOTIMPL;
01797     }
01798 
01799     create_nselem(This->doc, blockquoteW, &blockquote_elem);
01800     create_nselem(This->doc, pW, &p_elem);
01801 
01802     nsIDOMRange_ExtractContents(This->nsrange, &fragment);
01803     nsIDOMElement_AppendChild(p_elem, (nsIDOMNode*)fragment, &tmp);
01804     nsIDOMDocumentFragment_Release(fragment);
01805     nsIDOMNode_Release(tmp);
01806 
01807     nsIDOMElement_AppendChild(blockquote_elem, (nsIDOMNode*)p_elem, &tmp);
01808     nsIDOMElement_Release(p_elem);
01809     nsIDOMNode_Release(tmp);
01810 
01811     nsIDOMRange_InsertNode(This->nsrange, (nsIDOMNode*)blockquote_elem);
01812     nsIDOMElement_Release(blockquote_elem);
01813 
01814     return S_OK;
01815 }
01816 
01817 static HRESULT WINAPI RangeCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
01818         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
01819 {
01820     HTMLTxtRange *This = OLECMDTRG_THIS(iface);
01821 
01822     TRACE("(%p)->(%s %d %x %p %p)\n", This, debugstr_guid(pguidCmdGroup), nCmdID,
01823           nCmdexecopt, pvaIn, pvaOut);
01824 
01825     if(pguidCmdGroup && IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
01826         switch(nCmdID) {
01827         case IDM_INDENT:
01828             return exec_indent(This, pvaIn, pvaOut);
01829         default:
01830             FIXME("Unsupported cmdid %d of CGID_MSHTML\n", nCmdID);
01831         }
01832     }else {
01833         FIXME("Unsupported cmd %d of group %s\n", nCmdID, debugstr_guid(pguidCmdGroup));
01834     }
01835 
01836     return E_NOTIMPL;
01837 }
01838 
01839 #undef OLECMDTRG_THIS
01840 
01841 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
01842     RangeCommandTarget_QueryInterface,
01843     RangeCommandTarget_AddRef,
01844     RangeCommandTarget_Release,
01845     RangeCommandTarget_QueryStatus,
01846     RangeCommandTarget_Exec
01847 };
01848 
01849 HRESULT HTMLTxtRange_Create(HTMLDocumentNode *doc, nsIDOMRange *nsrange, IHTMLTxtRange **p)
01850 {
01851     HTMLTxtRange *ret;
01852 
01853     ret = heap_alloc(sizeof(HTMLTxtRange));
01854     if(!ret)
01855         return E_OUTOFMEMORY;
01856 
01857     ret->lpHTMLTxtRangeVtbl = &HTMLTxtRangeVtbl;
01858     ret->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
01859     ret->ref = 1;
01860 
01861     if(nsrange)
01862         nsIDOMRange_AddRef(nsrange);
01863     ret->nsrange = nsrange;
01864 
01865     ret->doc = doc;
01866     list_add_head(&doc->range_list, &ret->entry);
01867 
01868     *p = HTMLTXTRANGE(ret);
01869     return S_OK;
01870 }
01871 
01872 void detach_ranges(HTMLDocumentNode *This)
01873 {
01874     HTMLTxtRange *iter;
01875 
01876     LIST_FOR_EACH_ENTRY(iter, &This->range_list, HTMLTxtRange, entry) {
01877         iter->doc = NULL;
01878     }
01879 }

Generated on Sat May 26 2012 04:23:44 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.