server: Make timer id allocation algorithm conform to the Windows one.
[wine/wine-kai.git] / dlls / mshtml / txtrange.c
blob0ad3621e0f16db20b2255a65859c9312c40e6227
1 /*
2 * Copyright 2006-2007 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
35 #include "mshtml_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
39 static const WCHAR brW[] = {'b','r',0};
41 typedef struct {
42 const IHTMLTxtRangeVtbl *lpHTMLTxtRangeVtbl;
44 LONG ref;
46 nsIDOMRange *nsrange;
47 HTMLDocument *doc;
49 struct list entry;
50 } HTMLTxtRange;
52 #define HTMLTXTRANGE(x) ((IHTMLTxtRange*) &(x)->lpHTMLTxtRangeVtbl)
54 typedef struct {
55 WCHAR *buf;
56 DWORD len;
57 DWORD size;
58 } wstrbuf_t;
60 typedef struct {
61 PRUint16 type;
62 nsIDOMNode *node;
63 PRUint32 off;
64 nsAString str;
65 const PRUnichar *p;
66 } dompos_t;
68 typedef enum {
69 RU_UNKNOWN,
70 RU_CHAR,
71 RU_WORD,
72 RU_SENTENCE,
73 RU_TEXTEDIT
74 } range_unit_t;
76 static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface)
78 HTMLTxtRange *iter;
80 LIST_FOR_EACH_ENTRY(iter, &doc->range_list, HTMLTxtRange, entry) {
81 if(HTMLTXTRANGE(iter) == iface)
82 return iter;
85 ERR("Could not find range in document\n");
86 return NULL;
89 static range_unit_t string_to_unit(LPCWSTR str)
91 static const WCHAR characterW[] =
92 {'c','h','a','r','a','c','t','e','r',0};
93 static const WCHAR wordW[] =
94 {'w','o','r','d',0};
95 static const WCHAR sentenceW[] =
96 {'s','e','n','t','e','n','c','e',0};
97 static const WCHAR texteditW[] =
98 {'t','e','x','t','e','d','i','t',0};
100 if(!strcmpiW(str, characterW)) return RU_CHAR;
101 if(!strcmpiW(str, wordW)) return RU_WORD;
102 if(!strcmpiW(str, sentenceW)) return RU_SENTENCE;
103 if(!strcmpiW(str, texteditW)) return RU_TEXTEDIT;
105 return RU_UNKNOWN;
108 static int string_to_nscmptype(LPCWSTR str)
110 static const WCHAR seW[] = {'S','t','a','r','t','T','o','E','n','d',0};
111 static const WCHAR ssW[] = {'S','t','a','r','t','T','o','S','t','a','r','t',0};
112 static const WCHAR esW[] = {'E','n','d','T','o','S','t','a','r','t',0};
113 static const WCHAR eeW[] = {'E','n','d','T','o','E','n','d',0};
115 if(!strcmpiW(str, seW)) return NS_START_TO_END;
116 if(!strcmpiW(str, ssW)) return NS_START_TO_START;
117 if(!strcmpiW(str, esW)) return NS_END_TO_START;
118 if(!strcmpiW(str, eeW)) return NS_END_TO_END;
120 return -1;
123 static PRUint16 get_node_type(nsIDOMNode *node)
125 PRUint16 type = 0;
127 if(node)
128 nsIDOMNode_GetNodeType(node, &type);
130 return type;
133 static BOOL is_br_node(nsIDOMNode *node)
135 nsIDOMElement *elem;
136 nsAString tag_str;
137 const PRUnichar *tag;
138 BOOL ret = FALSE;
139 nsresult nsres;
141 nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem);
142 if(NS_FAILED(nsres))
143 return FALSE;
145 nsAString_Init(&tag_str, NULL);
146 nsIDOMElement_GetTagName(elem, &tag_str);
147 nsIDOMElement_Release(elem);
148 nsAString_GetData(&tag_str, &tag, 0);
150 if(!strcmpiW(tag, brW))
151 ret = TRUE;
153 nsAString_Finish(&tag_str);
155 return ret;
158 static inline void wstrbuf_init(wstrbuf_t *buf)
160 buf->len = 0;
161 buf->size = 16;
162 buf->buf = mshtml_alloc(buf->size * sizeof(WCHAR));
163 *buf->buf = 0;
166 static inline void wstrbuf_finish(wstrbuf_t *buf)
168 mshtml_free(buf->buf);
171 static void wstrbuf_append_len(wstrbuf_t *buf, LPCWSTR str, int len)
173 if(buf->len+len >= buf->size) {
174 buf->size = 2*buf->len+len;
175 buf->buf = mshtml_realloc(buf->buf, buf->size * sizeof(WCHAR));
178 memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
179 buf->len += len;
180 buf->buf[buf->len] = 0;
183 static inline void wstrbuf_append(wstrbuf_t *buf, LPCWSTR str)
185 wstrbuf_append_len(buf, str, strlenW(str));
188 static void wstrbuf_append_nodetxt(wstrbuf_t *buf, LPCWSTR str, int len)
190 const WCHAR *s = str;
191 WCHAR *d;
193 TRACE("%s\n", debugstr_wn(str, len));
195 if(buf->len+len >= buf->size) {
196 buf->size = 2*buf->len+len;
197 buf->buf = mshtml_realloc(buf->buf, buf->size * sizeof(WCHAR));
200 if(buf->len && isspaceW(buf->buf[buf->len-1])) {
201 while(s < str+len && isspaceW(*s))
202 s++;
205 d = buf->buf+buf->len;
206 while(s < str+len) {
207 if(isspaceW(*s)) {
208 *d++ = ' ';
209 s++;
210 while(s < str+len && isspaceW(*s))
211 s++;
212 }else {
213 *d++ = *s++;
217 buf->len = d - buf->buf;
218 *d = 0;
221 static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node)
224 switch(get_node_type(node)) {
225 case TEXT_NODE: {
226 nsIDOMText *nstext;
227 nsAString data_str;
228 const PRUnichar *data;
230 nsIDOMNode_QueryInterface(node, &IID_nsIDOMText, (void**)&nstext);
232 nsAString_Init(&data_str, NULL);
233 nsIDOMText_GetData(nstext, &data_str);
234 nsAString_GetData(&data_str, &data, NULL);
235 wstrbuf_append_nodetxt(buf, data, strlenW(data));
236 nsAString_Finish(&data_str);
238 nsIDOMText_Release(nstext);
240 break;
242 case ELEMENT_NODE:
243 if(is_br_node(node)) {
244 static const WCHAR endlW[] = {'\r','\n'};
245 wstrbuf_append_len(buf, endlW, 2);
250 static BOOL fill_nodestr(dompos_t *pos)
252 nsIDOMText *text;
253 nsresult nsres;
255 if(pos->type != TEXT_NODE)
256 return FALSE;
258 nsres = nsIDOMNode_QueryInterface(pos->node, &IID_nsIDOMText, (void**)&text);
259 if(NS_FAILED(nsres))
260 return FALSE;
262 nsAString_Init(&pos->str, NULL);
263 nsIDOMText_GetData(text, &pos->str);
264 nsIDOMText_Release(text);
265 nsAString_GetData(&pos->str, &pos->p, NULL);
267 if(pos->off == -1)
268 pos->off = *pos->p ? strlenW(pos->p)-1 : 0;
270 return TRUE;
273 static nsIDOMNode *next_node(nsIDOMNode *iter)
275 nsIDOMNode *ret, *tmp;
276 nsresult nsres;
278 if(!iter)
279 return NULL;
281 nsres = nsIDOMNode_GetFirstChild(iter, &ret);
282 if(NS_SUCCEEDED(nsres) && ret)
283 return ret;
285 nsIDOMNode_AddRef(iter);
287 do {
288 nsres = nsIDOMNode_GetNextSibling(iter, &ret);
289 if(NS_SUCCEEDED(nsres) && ret) {
290 nsIDOMNode_Release(iter);
291 return ret;
294 nsres = nsIDOMNode_GetParentNode(iter, &tmp);
295 nsIDOMNode_Release(iter);
296 iter = tmp;
297 }while(NS_SUCCEEDED(nsres) && iter);
299 return NULL;
302 static nsIDOMNode *prev_node(HTMLTxtRange *This, nsIDOMNode *iter)
304 nsIDOMNode *ret, *tmp;
305 nsresult nsres;
307 if(!iter) {
308 nsIDOMHTMLDocument *nshtmldoc;
309 nsIDOMHTMLElement *nselem;
310 nsIDOMDocument *nsdoc;
312 nsIWebNavigation_GetDocument(This->doc->nscontainer->navigation, &nsdoc);
313 nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMHTMLDocument, (void**)&nshtmldoc);
314 nsIDOMDocument_Release(nsdoc);
315 nsIDOMHTMLDocument_GetBody(nshtmldoc, &nselem);
316 nsIDOMHTMLDocument_Release(nshtmldoc);
318 nsIDOMElement_GetLastChild(nselem, &tmp);
319 if(!tmp)
320 return (nsIDOMNode*)nselem;
322 while(tmp) {
323 ret = tmp;
324 nsIDOMNode_GetLastChild(ret, &tmp);
327 nsIDOMElement_Release(nselem);
329 return ret;
332 nsres = nsIDOMNode_GetLastChild(iter, &ret);
333 if(NS_SUCCEEDED(nsres) && ret)
334 return ret;
336 nsIDOMNode_AddRef(iter);
338 do {
339 nsres = nsIDOMNode_GetPreviousSibling(iter, &ret);
340 if(NS_SUCCEEDED(nsres) && ret) {
341 nsIDOMNode_Release(iter);
342 return ret;
345 nsres = nsIDOMNode_GetParentNode(iter, &tmp);
346 nsIDOMNode_Release(iter);
347 iter = tmp;
348 }while(NS_SUCCEEDED(nsres) && iter);
350 return NULL;
353 static nsIDOMNode *get_child_node(nsIDOMNode *node, PRUint32 off)
355 nsIDOMNodeList *node_list;
356 nsIDOMNode *ret = NULL;
358 nsIDOMNode_GetChildNodes(node, &node_list);
359 nsIDOMNodeList_Item(node_list, off, &ret);
360 nsIDOMNodeList_Release(node_list);
362 return ret;
365 static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
367 nsIDOMNode *node;
368 PRInt32 off;
370 pos->p = NULL;
372 if(!start) {
373 PRBool collapsed;
374 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
375 start = collapsed;
378 if(start) {
379 nsIDOMRange_GetStartContainer(This->nsrange, &node);
380 nsIDOMRange_GetStartOffset(This->nsrange, &off);
381 }else {
382 nsIDOMRange_GetEndContainer(This->nsrange, &node);
383 nsIDOMRange_GetEndOffset(This->nsrange, &off);
386 pos->type = get_node_type(node);
387 if(pos->type == ELEMENT_NODE) {
388 if(start) {
389 pos->node = get_child_node(node, off);
390 pos->off = 0;
391 }else {
392 pos->node = off ? get_child_node(node, off-1) : prev_node(This, node);
393 pos->off = -1;
396 pos->type = get_node_type(pos->node);
397 nsIDOMNode_Release(node);
398 }else if(start) {
399 pos->node = node;
400 pos->off = off;
401 }else if(off) {
402 pos->node = node;
403 pos->off = off-1;
404 }else {
405 pos->node = prev_node(This, node);
406 pos->off = -1;
407 nsIDOMNode_Release(node);
410 if(pos->type == TEXT_NODE)
411 fill_nodestr(pos);
414 static void set_range_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos)
416 nsresult nsres;
418 if(start) {
419 if(pos->type == TEXT_NODE)
420 nsres = nsIDOMRange_SetStart(This->nsrange, pos->node, pos->off);
421 else
422 nsres = nsIDOMRange_SetStartBefore(This->nsrange, pos->node);
423 }else {
424 if(pos->type == TEXT_NODE && pos->p[pos->off+1])
425 nsres = nsIDOMRange_SetEnd(This->nsrange, pos->node, pos->off+1);
426 else
427 nsres = nsIDOMRange_SetEndAfter(This->nsrange, pos->node);
430 if(NS_FAILED(nsres))
431 ERR("failed: %p %08x\n", pos->node, nsres);
434 static inline void dompos_release(dompos_t *pos)
436 if(pos->node)
437 nsIDOMNode_Release(pos->node);
439 if(pos->p)
440 nsAString_Finish(&pos->str);
443 static inline void dompos_addref(dompos_t *pos)
445 if(pos->node)
446 nsIDOMNode_AddRef(pos->node);
448 if(pos->type == TEXT_NODE)
449 fill_nodestr(pos);
452 static inline BOOL dompos_cmp(const dompos_t *pos1, const dompos_t *pos2)
454 return pos1->node == pos2->node && pos1->off == pos2->off;
457 static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf)
459 nsIDOMNode *iter, *tmp;
460 dompos_t start_pos, end_pos;
461 PRBool collapsed;
463 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
464 if(collapsed) {
465 wstrbuf_finish(buf);
466 buf->buf = NULL;
467 buf->size = 0;
468 return;
471 get_cur_pos(This, FALSE, &end_pos);
472 get_cur_pos(This, TRUE, &start_pos);
474 if(start_pos.type == TEXT_NODE) {
475 if(start_pos.node == end_pos.node) {
476 wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, end_pos.off-start_pos.off+1);
477 iter = start_pos.node;
478 nsIDOMNode_AddRef(iter);
479 }else {
480 wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, strlenW(start_pos.p+start_pos.off));
481 iter = next_node(start_pos.node);
483 }else {
484 iter = start_pos.node;
485 nsIDOMNode_AddRef(iter);
488 while(iter != end_pos.node) {
489 wstrbuf_append_node(buf, iter);
490 tmp = next_node(iter);
491 nsIDOMNode_Release(iter);
492 iter = tmp;
495 nsIDOMNode_AddRef(end_pos.node);
497 if(start_pos.node != end_pos.node && !is_br_node(end_pos.node))
498 wstrbuf_append_nodetxt(buf, end_pos.p, end_pos.off+1);
500 nsIDOMNode_Release(iter);
501 dompos_release(&start_pos);
502 dompos_release(&end_pos);
504 if(buf->len) {
505 WCHAR *p;
507 for(p = buf->buf+buf->len-1; p >= buf->buf && isspaceW(*p); p--);
509 p = strchrW(p, '\r');
510 if(p)
511 *p = 0;
515 static WCHAR get_pos_char(const dompos_t *pos)
517 switch(pos->type) {
518 case TEXT_NODE:
519 return pos->p[pos->off];
520 case ELEMENT_NODE:
521 if(is_br_node(pos->node))
522 return '\n';
525 return 0;
528 static void end_space(const dompos_t *pos, dompos_t *new_pos)
530 const WCHAR *p;
532 *new_pos = *pos;
533 dompos_addref(new_pos);
535 if(pos->type != TEXT_NODE)
536 return;
538 p = new_pos->p+new_pos->off;
540 if(!*p || !isspace(*p))
541 return;
543 while(p[1] && isspace(p[1]))
544 p++;
546 new_pos->off = p - new_pos->p;
549 static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos)
551 nsIDOMNode *iter, *tmp;
552 dompos_t last_space, tmp_pos;
553 const WCHAR *p;
554 WCHAR cspace = 0;
556 if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off]) {
557 p = pos->p+pos->off;
559 if(isspace(*p))
560 while(isspaceW(*++p));
561 else
562 p++;
564 if(*p && isspaceW(*p)) {
565 cspace = ' ';
566 while(p[1] && isspaceW(p[1]))
567 p++;
570 if(*p) {
571 *new_pos = *pos;
572 new_pos->off = p - pos->p;
573 dompos_addref(new_pos);
575 return cspace ? cspace : *p;
576 }else {
577 last_space = *pos;
578 last_space.off = p - pos->p;
579 dompos_addref(&last_space);
583 iter = next_node(pos->node);
585 while(iter) {
586 switch(get_node_type(iter)) {
587 case TEXT_NODE:
588 tmp_pos.node = iter;
589 tmp_pos.type = TEXT_NODE;
590 dompos_addref(&tmp_pos);
592 p = tmp_pos.p;
594 if(!*p) {
595 dompos_release(&tmp_pos);
596 break;
597 }else if(isspaceW(*p)) {
598 if(cspace)
599 dompos_release(&last_space);
600 else
601 cspace = ' ';
603 while(p[1] && isspaceW(p[1]))
604 p++;
606 tmp_pos.off = p-tmp_pos.p;
608 if(!p[1]) {
609 last_space = tmp_pos;
610 break;
613 *new_pos = tmp_pos;
614 nsIDOMNode_Release(iter);
615 return cspace;
616 }else if(cspace) {
617 *new_pos = last_space;
618 dompos_release(&tmp_pos);
619 nsIDOMNode_Release(iter);
621 return cspace;
622 }else if(*p) {
623 tmp_pos.off = 0;
624 *new_pos = tmp_pos;
627 nsIDOMNode_Release(iter);
628 return *p;
630 case ELEMENT_NODE:
631 if(!is_br_node(iter))
632 break;
634 if(cspace)
635 dompos_release(&last_space);
636 cspace = '\n';
638 nsIDOMNode_AddRef(iter);
639 last_space.node = iter;
640 last_space.type = ELEMENT_NODE;
641 last_space.off = 0;
642 last_space.p = NULL;
645 tmp = iter;
646 iter = next_node(iter);
647 nsIDOMNode_Release(tmp);
650 if(cspace) {
651 *new_pos = last_space;
652 }else {
653 *new_pos = *pos;
654 dompos_addref(new_pos);
657 return cspace;
660 static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos)
662 nsIDOMNode *iter, *tmp;
663 const WCHAR *p;
664 BOOL skip_space = FALSE;
666 if(pos->type == TEXT_NODE && isspaceW(pos->p[pos->off]))
667 skip_space = TRUE;
669 if(pos->type == TEXT_NODE && pos->off) {
670 p = pos->p+pos->off-1;
672 if(skip_space) {
673 while(p >= pos->p && isspace(*p))
674 p--;
677 if(p >= pos->p) {
678 *new_pos = *pos;
679 new_pos->off = p-pos->p;
680 dompos_addref(new_pos);
681 return new_pos->p[new_pos->off];
685 iter = prev_node(This, pos->node);
687 while(iter) {
688 switch(get_node_type(iter)) {
689 case TEXT_NODE: {
690 dompos_t tmp_pos;
692 tmp_pos.node = iter;
693 tmp_pos.type = TEXT_NODE;
694 dompos_addref(&tmp_pos);
696 p = tmp_pos.p + strlenW(tmp_pos.p)-1;
698 if(skip_space) {
699 while(p >= tmp_pos.p && isspaceW(*p))
700 p--;
703 if(p < tmp_pos.p) {
704 dompos_release(&tmp_pos);
705 break;
708 tmp_pos.off = p-tmp_pos.p;
709 *new_pos = tmp_pos;
710 nsIDOMNode_Release(iter);
711 return *p;
714 case ELEMENT_NODE:
715 if(!is_br_node(iter))
716 break;
718 if(skip_space) {
719 skip_space = FALSE;
720 break;
723 new_pos->node = iter;
724 new_pos->type = ELEMENT_NODE;
725 new_pos->off = 0;
726 new_pos->p = NULL;
727 return '\n';
730 tmp = iter;
731 iter = prev_node(This, iter);
732 nsIDOMNode_Release(tmp);
735 *new_pos = *pos;
736 dompos_addref(new_pos);
737 return 0;
740 static long move_next_chars(long cnt, const dompos_t *pos, BOOL col, const dompos_t *bound_pos,
741 BOOL *bounded, dompos_t *new_pos)
743 dompos_t iter, tmp;
744 long ret = 0;
745 WCHAR c;
747 if(bounded)
748 *bounded = FALSE;
750 if(col)
751 ret++;
753 if(ret >= cnt) {
754 end_space(pos, new_pos);
755 return ret;
758 c = next_char(pos, &iter);
759 ret++;
761 while(ret < cnt) {
762 tmp = iter;
763 c = next_char(&tmp, &iter);
764 dompos_release(&tmp);
765 if(!c)
766 break;
768 ret++;
769 if(bound_pos && dompos_cmp(&tmp, bound_pos)) {
770 *bounded = TRUE;
771 ret++;
775 *new_pos = iter;
776 return ret;
779 static long move_prev_chars(HTMLTxtRange *This, long cnt, const dompos_t *pos, BOOL end,
780 const dompos_t *bound_pos, BOOL *bounded, dompos_t *new_pos)
782 dompos_t iter, tmp;
783 long ret = 0;
784 WCHAR c;
786 if(bounded)
787 *bounded = FALSE;
789 c = prev_char(This, pos, &iter);
790 if(c)
791 ret++;
793 while(c && ret < cnt) {
794 tmp = iter;
795 c = prev_char(This, &tmp, &iter);
796 dompos_release(&tmp);
797 if(!c) {
798 if(end)
799 ret++;
800 break;
803 ret++;
805 if(bound_pos && dompos_cmp(&iter, bound_pos)) {
806 *bounded = TRUE;
807 cnt--;
811 *new_pos = iter;
812 return bounded && *bounded ? ret+1 : ret;
815 static long find_prev_space(HTMLTxtRange *This, const dompos_t *pos, BOOL first_space, dompos_t *ret)
817 dompos_t iter, tmp;
818 WCHAR c;
820 c = prev_char(This, pos, &iter);
821 if(!c || (first_space && isspaceW(c))) {
822 *ret = iter;
823 return FALSE;
826 while(1) {
827 tmp = iter;
828 c = prev_char(This, &tmp, &iter);
829 if(!c || isspaceW(c)) {
830 dompos_release(&iter);
831 break;
833 dompos_release(&tmp);
836 *ret = tmp;
837 return TRUE;
840 static int find_word_end(const dompos_t *pos, dompos_t *ret)
842 dompos_t iter, tmp;
843 int cnt = 1;
844 WCHAR c;
845 c = get_pos_char(pos);
846 if(isspaceW(c)) {
847 *ret = *pos;
848 dompos_addref(ret);
849 return 0;
852 c = next_char(pos, &iter);
853 if(!c) {
854 *ret = iter;
855 return 0;
857 if(c == '\n') {
858 *ret = *pos;
859 dompos_addref(ret);
860 return 0;
863 while(c && !isspaceW(c)) {
864 tmp = iter;
865 c = next_char(&tmp, &iter);
866 if(c == '\n') {
867 dompos_release(&iter);
868 iter = tmp;
869 }else {
870 cnt++;
871 dompos_release(&tmp);
875 *ret = iter;
876 return cnt;
879 static long move_next_words(long cnt, const dompos_t *pos, dompos_t *new_pos)
881 dompos_t iter, tmp;
882 long ret = 0;
883 WCHAR c;
885 c = get_pos_char(pos);
886 if(isspaceW(c)) {
887 end_space(pos, &iter);
888 ret++;
889 }else {
890 c = next_char(pos, &iter);
891 if(c && isspaceW(c))
892 ret++;
895 while(c && ret < cnt) {
896 tmp = iter;
897 c = next_char(&tmp, &iter);
898 dompos_release(&tmp);
899 if(isspaceW(c))
900 ret++;
903 *new_pos = iter;
904 return ret;
907 static long move_prev_words(HTMLTxtRange *This, long cnt, const dompos_t *pos, dompos_t *new_pos)
909 dompos_t iter, tmp;
910 long ret = 0;
912 iter = *pos;
913 dompos_addref(&iter);
915 while(ret < cnt) {
916 if(!find_prev_space(This, &iter, FALSE, &tmp))
917 break;
919 dompos_release(&iter);
920 iter = tmp;
921 ret++;
924 *new_pos = iter;
925 return ret;
928 #define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface)
930 static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv)
932 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
934 *ppv = NULL;
936 if(IsEqualGUID(&IID_IUnknown, riid)) {
937 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
938 *ppv = HTMLTXTRANGE(This);
939 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
940 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
941 *ppv = HTMLTXTRANGE(This);
942 }else if(IsEqualGUID(&IID_IHTMLTxtRange, riid)) {
943 TRACE("(%p)->(IID_IHTMLTxtRange %p)\n", This, ppv);
944 *ppv = HTMLTXTRANGE(This);
947 if(*ppv) {
948 IUnknown_AddRef((IUnknown*)*ppv);
949 return S_OK;
952 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
953 return E_NOINTERFACE;
956 static ULONG WINAPI HTMLTxtRange_AddRef(IHTMLTxtRange *iface)
958 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
959 LONG ref = InterlockedIncrement(&This->ref);
961 TRACE("(%p) ref=%d\n", This, ref);
963 return ref;
966 static ULONG WINAPI HTMLTxtRange_Release(IHTMLTxtRange *iface)
968 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
969 LONG ref = InterlockedDecrement(&This->ref);
971 TRACE("(%p) ref=%d\n", This, ref);
973 if(!ref) {
974 if(This->nsrange)
975 nsISelection_Release(This->nsrange);
976 if(This->doc)
977 list_remove(&This->entry);
978 mshtml_free(This);
981 return ref;
984 static HRESULT WINAPI HTMLTxtRange_GetTypeInfoCount(IHTMLTxtRange *iface, UINT *pctinfo)
986 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
987 FIXME("(%p)->(%p)\n", This, pctinfo);
988 return E_NOTIMPL;
991 static HRESULT WINAPI HTMLTxtRange_GetTypeInfo(IHTMLTxtRange *iface, UINT iTInfo,
992 LCID lcid, ITypeInfo **ppTInfo)
994 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
995 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
996 return E_NOTIMPL;
999 static HRESULT WINAPI HTMLTxtRange_GetIDsOfNames(IHTMLTxtRange *iface, REFIID riid,
1000 LPOLESTR *rgszNames, UINT cNames,
1001 LCID lcid, DISPID *rgDispId)
1003 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1004 FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1005 lcid, rgDispId);
1006 return E_NOTIMPL;
1009 static HRESULT WINAPI HTMLTxtRange_Invoke(IHTMLTxtRange *iface, DISPID dispIdMember,
1010 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1011 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1013 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1014 FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1015 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1016 return E_NOTIMPL;
1019 static HRESULT WINAPI HTMLTxtRange_get_htmlText(IHTMLTxtRange *iface, BSTR *p)
1021 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1023 TRACE("(%p)->(%p)\n", This, p);
1025 *p = NULL;
1027 if(This->nsrange) {
1028 nsIDOMDocumentFragment *fragment;
1029 nsresult nsres;
1031 nsres = nsIDOMRange_CloneContents(This->nsrange, &fragment);
1032 if(NS_SUCCEEDED(nsres)) {
1033 const PRUnichar *nstext;
1034 nsAString nsstr;
1036 nsAString_Init(&nsstr, NULL);
1037 nsnode_to_nsstring((nsIDOMNode*)fragment, &nsstr);
1038 nsIDOMDocumentFragment_Release(fragment);
1040 nsAString_GetData(&nsstr, &nstext, NULL);
1041 *p = SysAllocString(nstext);
1043 nsAString_Finish(&nsstr);
1047 if(!*p) {
1048 const WCHAR emptyW[] = {0};
1049 *p = SysAllocString(emptyW);
1052 TRACE("return %s\n", debugstr_w(*p));
1053 return S_OK;
1056 static HRESULT WINAPI HTMLTxtRange_put_text(IHTMLTxtRange *iface, BSTR v)
1058 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1059 nsIDOMDocument *nsdoc;
1060 nsIDOMText *text_node;
1061 nsAString text_str;
1062 nsresult nsres;
1064 TRACE("(%p)->(%s)\n", This, debugstr_w(v));
1066 if(!This->doc)
1067 return MSHTML_E_NODOC;
1069 nsres = nsIWebNavigation_GetDocument(This->doc->nscontainer->navigation, &nsdoc);
1070 if(NS_FAILED(nsres)) {
1071 ERR("GetDocument failed: %08x\n", nsres);
1072 return S_OK;
1075 nsAString_Init(&text_str, v);
1076 nsres = nsIDOMDocument_CreateTextNode(nsdoc, &text_str, &text_node);
1077 nsIDOMDocument_Release(nsdoc);
1078 nsAString_Finish(&text_str);
1079 if(NS_FAILED(nsres)) {
1080 ERR("CreateTextNode failed: %08x\n", nsres);
1081 return S_OK;
1083 nsres = nsIDOMRange_DeleteContents(This->nsrange);
1084 if(NS_FAILED(nsres))
1085 ERR("DeleteContents failed: %08x\n", nsres);
1087 nsres = nsIDOMRange_InsertNode(This->nsrange, (nsIDOMNode*)text_node);
1088 if(NS_FAILED(nsres))
1089 ERR("InsertNode failed: %08x\n", nsres);
1091 nsres = nsIDOMRange_SetEndAfter(This->nsrange, (nsIDOMNode*)text_node);
1092 if(NS_FAILED(nsres))
1093 ERR("SetEndAfter failed: %08x\n", nsres);
1095 return IHTMLTxtRange_collapse(HTMLTXTRANGE(This), VARIANT_FALSE);
1098 static HRESULT WINAPI HTMLTxtRange_get_text(IHTMLTxtRange *iface, BSTR *p)
1100 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1101 wstrbuf_t buf;
1103 TRACE("(%p)->(%p)\n", This, p);
1105 *p = NULL;
1106 if(!This->nsrange)
1107 return S_OK;
1109 wstrbuf_init(&buf);
1110 range_to_string(This, &buf);
1111 if(buf.buf)
1112 *p = SysAllocString(buf.buf);
1113 wstrbuf_finish(&buf);
1115 TRACE("ret %s\n", debugstr_w(*p));
1116 return S_OK;
1119 static HRESULT WINAPI HTMLTxtRange_parentElement(IHTMLTxtRange *iface, IHTMLElement **parent)
1121 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1122 nsIDOMNode *nsnode, *tmp;
1123 HTMLDOMNode *node;
1125 TRACE("(%p)->(%p)\n", This, parent);
1127 nsIDOMRange_GetCommonAncestorContainer(This->nsrange, &nsnode);
1128 while(nsnode && get_node_type(nsnode) != ELEMENT_NODE) {
1129 nsIDOMNode_GetParentNode(nsnode, &tmp);
1130 nsIDOMNode_Release(nsnode);
1131 nsnode = tmp;
1134 if(!nsnode) {
1135 *parent = NULL;
1136 return S_OK;
1139 node = get_node(This->doc, nsnode);
1140 nsIDOMNode_Release(nsnode);
1142 return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(node), &IID_IHTMLElement, (void**)parent);
1145 static HRESULT WINAPI HTMLTxtRange_duplicate(IHTMLTxtRange *iface, IHTMLTxtRange **Duplicate)
1147 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1148 nsIDOMRange *nsrange = NULL;
1150 TRACE("(%p)->(%p)\n", This, Duplicate);
1152 nsIDOMRange_CloneRange(This->nsrange, &nsrange);
1153 *Duplicate = HTMLTxtRange_Create(This->doc, nsrange);
1154 nsIDOMRange_Release(nsrange);
1156 return S_OK;
1159 static HRESULT WINAPI HTMLTxtRange_inRange(IHTMLTxtRange *iface, IHTMLTxtRange *Range,
1160 VARIANT_BOOL *InRange)
1162 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1163 HTMLTxtRange *src_range;
1164 PRInt16 nsret = 0;
1165 nsresult nsres;
1167 TRACE("(%p)->(%p %p)\n", This, Range, InRange);
1169 *InRange = VARIANT_FALSE;
1171 src_range = get_range_object(This->doc, Range);
1172 if(!src_range)
1173 return E_FAIL;
1175 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_START_TO_START,
1176 src_range->nsrange, &nsret);
1177 if(NS_SUCCEEDED(nsres) && nsret <= 0) {
1178 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_END_TO_END,
1179 src_range->nsrange, &nsret);
1180 if(NS_SUCCEEDED(nsres) && nsret >= 0)
1181 *InRange = VARIANT_TRUE;
1184 if(NS_FAILED(nsres))
1185 ERR("CompareBoundaryPoints failed: %08x\n", nsres);
1187 return S_OK;
1190 static HRESULT WINAPI HTMLTxtRange_isEqual(IHTMLTxtRange *iface, IHTMLTxtRange *Range,
1191 VARIANT_BOOL *IsEqual)
1193 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1194 HTMLTxtRange *src_range;
1195 PRInt16 nsret = 0;
1196 nsresult nsres;
1198 TRACE("(%p)->(%p %p)\n", This, Range, IsEqual);
1200 *IsEqual = VARIANT_FALSE;
1202 src_range = get_range_object(This->doc, Range);
1203 if(!src_range)
1204 return E_FAIL;
1206 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_START_TO_START,
1207 src_range->nsrange, &nsret);
1208 if(NS_SUCCEEDED(nsres) && !nsret) {
1209 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_END_TO_END,
1210 src_range->nsrange, &nsret);
1211 if(NS_SUCCEEDED(nsres) && !nsret)
1212 *IsEqual = VARIANT_TRUE;
1215 if(NS_FAILED(nsres))
1216 ERR("CompareBoundaryPoints failed: %08x\n", nsres);
1218 return S_OK;
1221 static HRESULT WINAPI HTMLTxtRange_scrollIntoView(IHTMLTxtRange *iface, VARIANT_BOOL fStart)
1223 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1224 FIXME("(%p)->(%x)\n", This, fStart);
1225 return E_NOTIMPL;
1228 static HRESULT WINAPI HTMLTxtRange_collapse(IHTMLTxtRange *iface, VARIANT_BOOL Start)
1230 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1232 TRACE("(%p)->(%x)\n", This, Start);
1234 nsIDOMRange_Collapse(This->nsrange, Start != VARIANT_FALSE);
1235 return S_OK;
1238 static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIANT_BOOL *Success)
1240 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1241 range_unit_t unit;
1243 TRACE("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success);
1245 unit = string_to_unit(Unit);
1246 if(unit == RU_UNKNOWN)
1247 return E_INVALIDARG;
1249 *Success = VARIANT_FALSE;
1251 switch(unit) {
1252 case RU_WORD: {
1253 dompos_t end_pos, start_pos, new_start_pos, new_end_pos;
1254 PRBool collapsed;
1256 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
1258 get_cur_pos(This, TRUE, &start_pos);
1259 get_cur_pos(This, FALSE, &end_pos);
1261 if(find_word_end(&end_pos, &new_end_pos) || collapsed) {
1262 set_range_pos(This, FALSE, &new_end_pos);
1263 *Success = VARIANT_TRUE;
1266 if(start_pos.type && (get_pos_char(&end_pos) || !dompos_cmp(&new_end_pos, &end_pos))) {
1267 if(find_prev_space(This, &start_pos, TRUE, &new_start_pos)) {
1268 set_range_pos(This, TRUE, &new_start_pos);
1269 *Success = VARIANT_TRUE;
1271 dompos_release(&new_start_pos);
1274 dompos_release(&new_end_pos);
1275 dompos_release(&end_pos);
1276 dompos_release(&start_pos);
1278 break;
1281 case RU_TEXTEDIT: {
1282 nsIDOMDocument *nsdoc;
1283 nsIDOMHTMLDocument *nshtmldoc;
1284 nsIDOMHTMLElement *nsbody = NULL;
1285 nsresult nsres;
1287 nsres = nsIWebNavigation_GetDocument(This->doc->nscontainer->navigation, &nsdoc);
1288 if(NS_FAILED(nsres) || !nsdoc) {
1289 ERR("GetDocument failed: %08x\n", nsres);
1290 break;
1293 nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMHTMLDocument, (void**)&nshtmldoc);
1294 nsIDOMDocument_Release(nsdoc);
1296 nsres = nsIDOMHTMLDocument_GetBody(nshtmldoc, &nsbody);
1297 nsIDOMHTMLDocument_Release(nshtmldoc);
1298 if(NS_FAILED(nsres) || !nsbody) {
1299 ERR("Could not get body: %08x\n", nsres);
1300 break;
1303 nsres = nsIDOMRange_SelectNodeContents(This->nsrange, (nsIDOMNode*)nsbody);
1304 nsIDOMHTMLElement_Release(nsbody);
1305 if(NS_FAILED(nsres)) {
1306 ERR("Collapse failed: %08x\n", nsres);
1307 break;
1310 *Success = VARIANT_TRUE;
1311 break;
1314 default:
1315 FIXME("Unimplemented unit %s\n", debugstr_w(Unit));
1318 return S_OK;
1321 static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit,
1322 long Count, long *ActualCount)
1324 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1325 range_unit_t unit;
1327 TRACE("(%p)->(%s %ld %p)\n", This, debugstr_w(Unit), Count, ActualCount);
1329 unit = string_to_unit(Unit);
1330 if(unit == RU_UNKNOWN)
1331 return E_INVALIDARG;
1333 if(!Count) {
1334 *ActualCount = 0;
1335 return IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
1338 switch(unit) {
1339 case RU_CHAR: {
1340 dompos_t cur_pos, new_pos;
1342 get_cur_pos(This, TRUE, &cur_pos);
1344 if(Count > 0) {
1345 *ActualCount = move_next_chars(Count, &cur_pos, TRUE, NULL, NULL, &new_pos);
1346 set_range_pos(This, FALSE, &new_pos);
1347 dompos_release(&new_pos);
1349 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE);
1350 }else {
1351 *ActualCount = -move_prev_chars(This, -Count, &cur_pos, FALSE, NULL, NULL, &new_pos);
1352 set_range_pos(This, TRUE, &new_pos);
1353 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
1354 dompos_release(&new_pos);
1357 dompos_release(&cur_pos);
1358 break;
1361 case RU_WORD: {
1362 dompos_t cur_pos, new_pos;
1364 get_cur_pos(This, TRUE, &cur_pos);
1366 if(Count > 0) {
1367 *ActualCount = move_next_words(Count, &cur_pos, &new_pos);
1368 set_range_pos(This, FALSE, &new_pos);
1369 dompos_release(&new_pos);
1370 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE);
1371 }else {
1372 *ActualCount = -move_prev_words(This, -Count, &cur_pos, &new_pos);
1373 set_range_pos(This, TRUE, &new_pos);
1374 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
1375 dompos_release(&new_pos);
1378 dompos_release(&cur_pos);
1379 break;
1382 default:
1383 FIXME("unimplemented unit %s\n", debugstr_w(Unit));
1386 TRACE("ret %ld\n", *ActualCount);
1387 return S_OK;
1390 static HRESULT WINAPI HTMLTxtRange_moveStart(IHTMLTxtRange *iface, BSTR Unit,
1391 long Count, long *ActualCount)
1393 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1394 range_unit_t unit;
1396 TRACE("(%p)->(%s %ld %p)\n", This, debugstr_w(Unit), Count, ActualCount);
1398 unit = string_to_unit(Unit);
1399 if(unit == RU_UNKNOWN)
1400 return E_INVALIDARG;
1402 if(!Count) {
1403 *ActualCount = 0;
1404 return S_OK;
1407 switch(unit) {
1408 case RU_CHAR: {
1409 dompos_t start_pos, end_pos, new_pos;
1410 PRBool collapsed;
1412 get_cur_pos(This, TRUE, &start_pos);
1413 get_cur_pos(This, FALSE, &end_pos);
1414 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
1416 if(Count > 0) {
1417 BOOL bounded;
1419 *ActualCount = move_next_chars(Count, &start_pos, collapsed, &end_pos, &bounded, &new_pos);
1420 set_range_pos(This, !bounded, &new_pos);
1421 if(bounded)
1422 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE);
1423 }else {
1424 *ActualCount = -move_prev_chars(This, -Count, &start_pos, FALSE, NULL, NULL, &new_pos);
1425 set_range_pos(This, TRUE, &new_pos);
1428 dompos_release(&start_pos);
1429 dompos_release(&end_pos);
1430 dompos_release(&new_pos);
1431 break;
1434 default:
1435 FIXME("unimplemented unit %s\n", debugstr_w(Unit));
1438 return S_OK;
1441 static HRESULT WINAPI HTMLTxtRange_moveEnd(IHTMLTxtRange *iface, BSTR Unit,
1442 long Count, long *ActualCount)
1444 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1445 range_unit_t unit;
1447 TRACE("(%p)->(%s %ld %p)\n", This, debugstr_w(Unit), Count, ActualCount);
1449 unit = string_to_unit(Unit);
1450 if(unit == RU_UNKNOWN)
1451 return E_INVALIDARG;
1453 if(!Count) {
1454 *ActualCount = 0;
1455 return S_OK;
1458 switch(unit) {
1459 case RU_CHAR: {
1460 dompos_t start_pos, end_pos, new_pos;
1461 PRBool collapsed;
1463 get_cur_pos(This, TRUE, &start_pos);
1464 get_cur_pos(This, FALSE, &end_pos);
1465 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed);
1467 if(Count > 0) {
1468 *ActualCount = move_next_chars(Count, &end_pos, collapsed, NULL, NULL, &new_pos);
1469 set_range_pos(This, FALSE, &new_pos);
1470 }else {
1471 BOOL bounded;
1473 *ActualCount = -move_prev_chars(This, -Count, &end_pos, TRUE, &start_pos, &bounded, &new_pos);
1474 set_range_pos(This, bounded, &new_pos);
1475 if(bounded)
1476 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE);
1479 dompos_release(&start_pos);
1480 dompos_release(&end_pos);
1481 dompos_release(&new_pos);
1482 break;
1485 default:
1486 FIXME("unimplemented unit %s\n", debugstr_w(Unit));
1489 return S_OK;
1492 static HRESULT WINAPI HTMLTxtRange_select(IHTMLTxtRange *iface)
1494 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1496 TRACE("(%p)\n", This);
1498 if(This->doc->nscontainer) {
1499 nsIDOMWindow *dom_window = NULL;
1500 nsISelection *nsselection;
1502 nsIWebBrowser_GetContentDOMWindow(This->doc->nscontainer->webbrowser, &dom_window);
1503 nsIDOMWindow_GetSelection(dom_window, &nsselection);
1504 nsIDOMWindow_Release(dom_window);
1506 nsISelection_RemoveAllRanges(nsselection);
1507 nsISelection_AddRange(nsselection, This->nsrange);
1509 nsISelection_Release(nsselection);
1512 return S_OK;
1515 static HRESULT WINAPI HTMLTxtRange_pasteHTML(IHTMLTxtRange *iface, BSTR html)
1517 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1518 FIXME("(%p)->(%s)\n", This, debugstr_w(html));
1519 return E_NOTIMPL;
1522 static HRESULT WINAPI HTMLTxtRange_moveToElementText(IHTMLTxtRange *iface, IHTMLElement *element)
1524 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1525 FIXME("(%p)->(%p)\n", This, element);
1526 return E_NOTIMPL;
1529 static HRESULT WINAPI HTMLTxtRange_setEndPoint(IHTMLTxtRange *iface, BSTR how,
1530 IHTMLTxtRange *SourceRange)
1532 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1533 FIXME("(%p)->(%s %p)\n", This, debugstr_w(how), SourceRange);
1534 return E_NOTIMPL;
1537 static HRESULT WINAPI HTMLTxtRange_compareEndPoints(IHTMLTxtRange *iface, BSTR how,
1538 IHTMLTxtRange *SourceRange, long *ret)
1540 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1541 HTMLTxtRange *src_range;
1542 PRInt16 nsret = 0;
1543 int nscmpt;
1544 nsresult nsres;
1546 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(how), SourceRange, ret);
1548 nscmpt = string_to_nscmptype(how);
1549 if(nscmpt == -1)
1550 return E_INVALIDARG;
1552 src_range = get_range_object(This->doc, SourceRange);
1553 if(!src_range)
1554 return E_FAIL;
1556 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, nscmpt, src_range->nsrange, &nsret);
1557 if(NS_FAILED(nsres))
1558 ERR("CompareBoundaryPoints failed: %08x\n", nsres);
1560 *ret = nsret;
1561 return S_OK;
1564 static HRESULT WINAPI HTMLTxtRange_findText(IHTMLTxtRange *iface, BSTR String,
1565 long count, long Flags, VARIANT_BOOL *Success)
1567 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1568 FIXME("(%p)->(%s %ld %08lx %p)\n", This, debugstr_w(String), count, Flags, Success);
1569 return E_NOTIMPL;
1572 static HRESULT WINAPI HTMLTxtRange_moveToPoint(IHTMLTxtRange *iface, long x, long y)
1574 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1575 FIXME("(%p)->(%ld %ld)\n", This, x, y);
1576 return E_NOTIMPL;
1579 static HRESULT WINAPI HTMLTxtRange_getBookmark(IHTMLTxtRange *iface, BSTR *Bookmark)
1581 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1582 FIXME("(%p)->(%p)\n", This, Bookmark);
1583 return E_NOTIMPL;
1586 static HRESULT WINAPI HTMLTxtRange_moveToBookmark(IHTMLTxtRange *iface, BSTR Bookmark,
1587 VARIANT_BOOL *Success)
1589 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1590 FIXME("(%p)->(%s %p)\n", This, debugstr_w(Bookmark), Success);
1591 return E_NOTIMPL;
1594 static HRESULT WINAPI HTMLTxtRange_queryCommandSupported(IHTMLTxtRange *iface, BSTR cmdID,
1595 VARIANT_BOOL *pfRet)
1597 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1598 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
1599 return E_NOTIMPL;
1602 static HRESULT WINAPI HTMLTxtRange_queryCommandEnabled(IHTMLTxtRange *iface, BSTR cmdID,
1603 VARIANT_BOOL *pfRet)
1605 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1606 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
1607 return E_NOTIMPL;
1610 static HRESULT WINAPI HTMLTxtRange_queryCommandState(IHTMLTxtRange *iface, BSTR cmdID,
1611 VARIANT_BOOL *pfRet)
1613 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1614 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
1615 return E_NOTIMPL;
1618 static HRESULT WINAPI HTMLTxtRange_queryCommandIndeterm(IHTMLTxtRange *iface, BSTR cmdID,
1619 VARIANT_BOOL *pfRet)
1621 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1622 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
1623 return E_NOTIMPL;
1626 static HRESULT WINAPI HTMLTxtRange_queryCommandText(IHTMLTxtRange *iface, BSTR cmdID,
1627 BSTR *pcmdText)
1629 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1630 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdText);
1631 return E_NOTIMPL;
1634 static HRESULT WINAPI HTMLTxtRange_queryCommandValue(IHTMLTxtRange *iface, BSTR cmdID,
1635 VARIANT *pcmdValue)
1637 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1638 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdValue);
1639 return E_NOTIMPL;
1642 static HRESULT WINAPI HTMLTxtRange_execCommand(IHTMLTxtRange *iface, BSTR cmdID,
1643 VARIANT_BOOL showUI, VARIANT value, VARIANT_BOOL *pfRet)
1645 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1646 FIXME("(%p)->(%s %x v %p)\n", This, debugstr_w(cmdID), showUI, pfRet);
1647 return E_NOTIMPL;
1650 static HRESULT WINAPI HTMLTxtRange_execCommandShowHelp(IHTMLTxtRange *iface, BSTR cmdID,
1651 VARIANT_BOOL *pfRet)
1653 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
1654 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
1655 return E_NOTIMPL;
1658 #undef HTMLTXTRANGE_THIS
1660 static const IHTMLTxtRangeVtbl HTMLTxtRangeVtbl = {
1661 HTMLTxtRange_QueryInterface,
1662 HTMLTxtRange_AddRef,
1663 HTMLTxtRange_Release,
1664 HTMLTxtRange_GetTypeInfoCount,
1665 HTMLTxtRange_GetTypeInfo,
1666 HTMLTxtRange_GetIDsOfNames,
1667 HTMLTxtRange_Invoke,
1668 HTMLTxtRange_get_htmlText,
1669 HTMLTxtRange_put_text,
1670 HTMLTxtRange_get_text,
1671 HTMLTxtRange_parentElement,
1672 HTMLTxtRange_duplicate,
1673 HTMLTxtRange_inRange,
1674 HTMLTxtRange_isEqual,
1675 HTMLTxtRange_scrollIntoView,
1676 HTMLTxtRange_collapse,
1677 HTMLTxtRange_expand,
1678 HTMLTxtRange_move,
1679 HTMLTxtRange_moveStart,
1680 HTMLTxtRange_moveEnd,
1681 HTMLTxtRange_select,
1682 HTMLTxtRange_pasteHTML,
1683 HTMLTxtRange_moveToElementText,
1684 HTMLTxtRange_setEndPoint,
1685 HTMLTxtRange_compareEndPoints,
1686 HTMLTxtRange_findText,
1687 HTMLTxtRange_moveToPoint,
1688 HTMLTxtRange_getBookmark,
1689 HTMLTxtRange_moveToBookmark,
1690 HTMLTxtRange_queryCommandSupported,
1691 HTMLTxtRange_queryCommandEnabled,
1692 HTMLTxtRange_queryCommandState,
1693 HTMLTxtRange_queryCommandIndeterm,
1694 HTMLTxtRange_queryCommandText,
1695 HTMLTxtRange_queryCommandValue,
1696 HTMLTxtRange_execCommand,
1697 HTMLTxtRange_execCommandShowHelp
1700 IHTMLTxtRange *HTMLTxtRange_Create(HTMLDocument *doc, nsIDOMRange *nsrange)
1702 HTMLTxtRange *ret = mshtml_alloc(sizeof(HTMLTxtRange));
1704 ret->lpHTMLTxtRangeVtbl = &HTMLTxtRangeVtbl;
1705 ret->ref = 1;
1707 if(nsrange)
1708 nsIDOMRange_AddRef(nsrange);
1709 ret->nsrange = nsrange;
1711 ret->doc = doc;
1712 list_add_head(&doc->range_list, &ret->entry);
1714 return HTMLTXTRANGE(ret);
1717 void detach_ranges(HTMLDocument *This)
1719 HTMLTxtRange *iter;
1721 LIST_FOR_EACH_ENTRY(iter, &This->range_list, HTMLTxtRange, entry) {
1722 iter->doc = NULL;