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
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};
42 const IHTMLTxtRangeVtbl
*lpHTMLTxtRangeVtbl
;
52 #define HTMLTXTRANGE(x) ((IHTMLTxtRange*) &(x)->lpHTMLTxtRangeVtbl)
76 static HTMLTxtRange
*get_range_object(HTMLDocument
*doc
, IHTMLTxtRange
*iface
)
80 LIST_FOR_EACH_ENTRY(iter
, &doc
->range_list
, HTMLTxtRange
, entry
) {
81 if(HTMLTXTRANGE(iter
) == iface
)
85 ERR("Could not find range in document\n");
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
[] =
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
;
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
;
123 static PRUint16
get_node_type(nsIDOMNode
*node
)
125 PRUint16 type
= 0xfff;
128 nsIDOMNode_GetNodeType(node
, &type
);
133 static BOOL
is_br_node(nsIDOMNode
*node
)
137 const PRUnichar
*tag
;
141 nsres
= nsIDOMNode_QueryInterface(node
, &IID_nsIDOMElement
, (void**)&elem
);
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
))
153 nsAString_Finish(&tag_str
);
158 static inline void wstrbuf_init(wstrbuf_t
*buf
)
162 buf
->buf
= mshtml_alloc(buf
->size
* sizeof(WCHAR
));
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
));
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
;
193 if(buf
->len
+len
>= buf
->size
) {
194 buf
->size
= 2*buf
->len
+len
;
195 buf
->buf
= mshtml_realloc(buf
->buf
, buf
->size
* sizeof(WCHAR
));
198 if(buf
->len
&& isspaceW(buf
->buf
[buf
->len
-1])) {
199 while(s
< str
+len
&& isspaceW(*s
))
203 d
= buf
->buf
+buf
->len
;
208 while(s
< str
+len
&& isspaceW(*s
))
215 buf
->len
= d
- buf
->buf
;
219 static void wstrbuf_append_node(wstrbuf_t
*buf
, nsIDOMNode
*node
)
222 switch(get_node_type(node
)) {
226 const PRUnichar
*data
;
228 nsIDOMNode_QueryInterface(node
, &IID_nsIDOMText
, (void**)&nstext
);
230 nsAString_Init(&data_str
, NULL
);
231 nsIDOMText_GetData(nstext
, &data_str
);
232 nsAString_GetData(&data_str
, &data
, NULL
);
233 wstrbuf_append_nodetxt(buf
, data
, strlenW(data
));
234 nsAString_Finish(&data_str
);
236 nsIDOMText_Release(nstext
);
241 if(is_br_node(node
)) {
242 static const WCHAR endlW
[] = {'\r','\n'};
243 wstrbuf_append_len(buf
, endlW
, 2);
248 static BOOL
fill_nodestr(dompos_t
*pos
)
253 if(pos
->type
!= TEXT_NODE
)
256 nsres
= nsIDOMNode_QueryInterface(pos
->node
, &IID_nsIDOMText
, (void**)&text
);
260 nsAString_Init(&pos
->str
, NULL
);
261 nsIDOMText_GetData(text
, &pos
->str
);
262 nsIDOMText_Release(text
);
263 nsAString_GetData(&pos
->str
, &pos
->p
, NULL
);
268 static nsIDOMNode
*next_node(nsIDOMNode
*iter
)
270 nsIDOMNode
*ret
, *tmp
;
276 nsres
= nsIDOMNode_GetFirstChild(iter
, &ret
);
277 if(NS_SUCCEEDED(nsres
) && ret
)
280 nsIDOMNode_AddRef(iter
);
283 nsres
= nsIDOMNode_GetNextSibling(iter
, &ret
);
284 if(NS_SUCCEEDED(nsres
) && ret
) {
285 nsIDOMNode_Release(iter
);
289 nsres
= nsIDOMNode_GetParentNode(iter
, &tmp
);
290 nsIDOMNode_Release(iter
);
292 }while(NS_SUCCEEDED(nsres
) && iter
);
297 static nsIDOMNode
*prev_node(HTMLTxtRange
*This
, nsIDOMNode
*iter
)
299 nsIDOMNode
*ret
, *tmp
;
303 nsIDOMHTMLDocument
*nshtmldoc
;
304 nsIDOMHTMLElement
*nselem
;
305 nsIDOMDocument
*nsdoc
;
307 nsIWebNavigation_GetDocument(This
->doc
->nscontainer
->navigation
, &nsdoc
);
308 nsIDOMDocument_QueryInterface(nsdoc
, &IID_nsIDOMHTMLDocument
, (void**)&nshtmldoc
);
309 nsIDOMDocument_Release(nsdoc
);
310 nsIDOMHTMLDocument_GetBody(nshtmldoc
, &nselem
);
311 nsIDOMHTMLDocument_Release(nshtmldoc
);
313 nsIDOMElement_GetLastChild(nselem
, &tmp
);
315 return (nsIDOMNode
*)nselem
;
319 nsIDOMNode_GetLastChild(ret
, &tmp
);
322 nsIDOMElement_Release(nselem
);
327 nsres
= nsIDOMNode_GetLastChild(iter
, &ret
);
328 if(NS_SUCCEEDED(nsres
) && ret
)
331 nsIDOMNode_AddRef(iter
);
334 nsres
= nsIDOMNode_GetPreviousSibling(iter
, &ret
);
335 if(NS_SUCCEEDED(nsres
) && ret
) {
336 nsIDOMNode_Release(iter
);
340 nsres
= nsIDOMNode_GetParentNode(iter
, &tmp
);
341 nsIDOMNode_Release(iter
);
343 }while(NS_SUCCEEDED(nsres
) && iter
);
348 static nsIDOMNode
*get_child_node(nsIDOMNode
*node
, PRUint32 off
)
350 nsIDOMNodeList
*node_list
;
351 nsIDOMNode
*ret
= NULL
;
353 nsIDOMNode_GetChildNodes(node
, &node_list
);
354 nsIDOMNodeList_Item(node_list
, off
, &ret
);
355 nsIDOMNodeList_Release(node_list
);
360 static void get_cur_pos(HTMLTxtRange
*This
, BOOL start
, dompos_t
*pos
)
369 nsIDOMRange_GetCollapsed(This
->nsrange
, &collapsed
);
374 nsIDOMRange_GetStartContainer(This
->nsrange
, &node
);
375 nsIDOMRange_GetStartOffset(This
->nsrange
, &off
);
377 nsIDOMRange_GetEndContainer(This
->nsrange
, &node
);
378 nsIDOMRange_GetEndOffset(This
->nsrange
, &off
);
381 pos
->type
= get_node_type(node
);
382 if(pos
->type
== ELEMENT_NODE
) {
384 pos
->node
= get_child_node(node
, off
);
387 pos
->node
= off
? get_child_node(node
, off
-1) : prev_node(This
, node
);
391 pos
->type
= get_node_type(pos
->node
);
392 nsIDOMNode_Release(node
);
400 pos
->node
= prev_node(This
, node
);
402 nsIDOMNode_Release(node
);
405 if(pos
->type
== TEXT_NODE
)
409 static void set_range_pos(HTMLTxtRange
*This
, BOOL start
, dompos_t
*pos
)
414 if(pos
->type
== TEXT_NODE
)
415 nsres
= nsIDOMRange_SetStart(This
->nsrange
, pos
->node
, pos
->off
);
417 nsres
= nsIDOMRange_SetStartBefore(This
->nsrange
, pos
->node
);
419 if(pos
->type
== TEXT_NODE
)
420 nsres
= nsIDOMRange_SetEnd(This
->nsrange
, pos
->node
, pos
->off
+1);
422 nsres
= nsIDOMRange_SetEndAfter(This
->nsrange
, pos
->node
);
426 ERR("failed: %p %08x\n", pos
->node
, nsres
);
429 static inline void dompos_release(dompos_t
*pos
)
432 nsIDOMNode_Release(pos
->node
);
435 nsAString_Finish(&pos
->str
);
438 static inline void dompos_addref(dompos_t
*pos
)
441 nsIDOMNode_AddRef(pos
->node
);
443 if(pos
->type
== TEXT_NODE
)
447 static inline BOOL
dompos_cmp(const dompos_t
*pos1
, const dompos_t
*pos2
)
449 return pos1
->node
== pos2
->node
&& pos1
->off
== pos2
->off
;
452 static void range_to_string(HTMLTxtRange
*This
, wstrbuf_t
*buf
)
454 nsIDOMNode
*iter
, *tmp
;
455 dompos_t start_pos
, end_pos
;
458 nsIDOMRange_GetCollapsed(This
->nsrange
, &collapsed
);
466 get_cur_pos(This
, FALSE
, &end_pos
);
467 get_cur_pos(This
, TRUE
, &start_pos
);
469 if(start_pos
.type
== TEXT_NODE
) {
470 if(start_pos
.node
== end_pos
.node
) {
471 wstrbuf_append_nodetxt(buf
, start_pos
.p
+start_pos
.off
, end_pos
.off
-start_pos
.off
+1);
472 iter
= start_pos
.node
;
473 nsIDOMNode_AddRef(iter
);
475 wstrbuf_append_nodetxt(buf
, start_pos
.p
+start_pos
.off
, strlenW(start_pos
.p
+start_pos
.off
));
476 iter
= next_node(start_pos
.node
);
479 iter
= start_pos
.node
;
480 nsIDOMNode_AddRef(iter
);
483 while(iter
!= end_pos
.node
) {
484 wstrbuf_append_node(buf
, iter
);
485 tmp
= next_node(iter
);
486 nsIDOMNode_Release(iter
);
490 nsIDOMNode_AddRef(end_pos
.node
);
492 if(start_pos
.node
!= end_pos
.node
&& !is_br_node(end_pos
.node
))
493 wstrbuf_append_nodetxt(buf
, end_pos
.p
, end_pos
.off
+1);
495 nsIDOMNode_Release(iter
);
496 dompos_release(&start_pos
);
497 dompos_release(&end_pos
);
502 for(p
= buf
->buf
+buf
->len
-1; p
>= buf
->buf
&& isspaceW(*p
); p
--);
504 p
= strchrW(p
, '\r');
510 static WCHAR
get_pos_char(const dompos_t
*pos
)
514 return pos
->p
[pos
->off
];
516 if(is_br_node(pos
->node
))
523 static WCHAR
next_char(const dompos_t
*pos
, dompos_t
*new_pos
)
525 nsIDOMNode
*iter
, *tmp
;
526 dompos_t last_space
, tmp_pos
;
530 if(pos
->type
== TEXT_NODE
&& pos
->off
!= -1 && pos
->p
[pos
->off
]) {
531 p
= pos
->p
+pos
->off
+1;
532 if(*p
&& isspaceW(*p
)) {
534 while(p
[1] && isspaceW(p
[1]))
540 new_pos
->off
= p
- pos
->p
;
541 dompos_addref(new_pos
);
546 last_space
.off
= p
- pos
->p
;
547 dompos_addref(&last_space
);
551 iter
= next_node(pos
->node
);
554 switch(get_node_type(iter
)) {
557 tmp_pos
.type
= TEXT_NODE
;
558 dompos_addref(&tmp_pos
);
563 dompos_release(&tmp_pos
);
565 }else if(isspaceW(*p
)) {
567 dompos_release(&last_space
);
571 while(p
[1] && isspaceW(p
[1]))
574 tmp_pos
.off
= p
-tmp_pos
.p
;
577 last_space
= tmp_pos
;
582 nsIDOMNode_Release(iter
);
585 *new_pos
= last_space
;
586 dompos_release(&tmp_pos
);
587 nsIDOMNode_Release(iter
);
595 nsIDOMNode_Release(iter
);
599 if(!is_br_node(iter
))
603 dompos_release(&last_space
);
606 nsIDOMNode_AddRef(iter
);
607 last_space
.node
= iter
;
608 last_space
.type
= ELEMENT_NODE
;
614 iter
= next_node(iter
);
615 nsIDOMNode_Release(tmp
);
619 *new_pos
= last_space
;
622 dompos_addref(new_pos
);
628 static WCHAR
prev_char(HTMLTxtRange
*This
, const dompos_t
*pos
, dompos_t
*new_pos
)
630 nsIDOMNode
*iter
, *tmp
;
632 BOOL skip_space
= FALSE
;
634 if(pos
->type
== TEXT_NODE
&& isspaceW(pos
->p
[pos
->off
]))
637 if(pos
->type
== TEXT_NODE
&& pos
->off
) {
638 p
= pos
->p
+pos
->off
-1;
641 while(p
>= pos
->p
&& isspace(*p
))
647 new_pos
->off
= p
-pos
->p
;
648 dompos_addref(new_pos
);
649 return new_pos
->p
[new_pos
->off
];
653 iter
= prev_node(This
, pos
->node
);
656 switch(get_node_type(iter
)) {
661 tmp_pos
.type
= TEXT_NODE
;
662 dompos_addref(&tmp_pos
);
664 p
= tmp_pos
.p
+ strlenW(tmp_pos
.p
)-1;
667 while(p
>= tmp_pos
.p
&& isspaceW(*p
))
672 dompos_release(&tmp_pos
);
676 tmp_pos
.off
= p
-tmp_pos
.p
;
678 nsIDOMNode_Release(iter
);
683 if(!is_br_node(iter
))
691 new_pos
->node
= iter
;
692 new_pos
->type
= ELEMENT_NODE
;
699 iter
= prev_node(This
, iter
);
700 nsIDOMNode_Release(tmp
);
704 dompos_addref(new_pos
);
708 static long move_next_chars(long cnt
, const dompos_t
*pos
, BOOL col
, const dompos_t
*bound_pos
,
709 BOOL
*bounded
, dompos_t
*new_pos
)
723 dompos_addref(new_pos
);
727 c
= next_char(pos
, &iter
);
732 c
= next_char(&tmp
, &iter
);
733 dompos_release(&tmp
);
738 if(bound_pos
&& dompos_cmp(&tmp
, bound_pos
)) {
748 static long move_prev_chars(HTMLTxtRange
*This
, long cnt
, const dompos_t
*pos
, BOOL end
,
749 const dompos_t
*bound_pos
, BOOL
*bounded
, dompos_t
*new_pos
)
758 c
= prev_char(This
, pos
, &iter
);
762 while(c
&& ret
< cnt
) {
764 c
= prev_char(This
, &tmp
, &iter
);
765 dompos_release(&tmp
);
774 if(bound_pos
&& dompos_cmp(&iter
, bound_pos
))
782 static BOOL
find_next_space(const dompos_t
*pos
, dompos_t
*ret
)
787 c
= next_char(pos
, &iter
);
793 while(c
&& !isspaceW(c
)) {
795 c
= next_char(&tmp
, &iter
);
796 dompos_release(&tmp
);
803 static long find_prev_space(HTMLTxtRange
*This
, const dompos_t
*pos
, BOOL first_space
, dompos_t
*ret
)
808 c
= prev_char(This
, pos
, &iter
);
809 if(!c
|| (first_space
&& isspaceW(c
))) {
816 c
= prev_char(This
, &tmp
, &iter
);
817 if(!c
|| isspaceW(c
)) {
818 dompos_release(&iter
);
821 dompos_release(&tmp
);
828 static long move_next_words(long cnt
, const dompos_t
*pos
, dompos_t
*new_pos
)
834 dompos_addref(&iter
);
837 if(!find_next_space(&iter
, &tmp
))
841 dompos_release(&iter
);
849 static long move_prev_words(HTMLTxtRange
*This
, long cnt
, const dompos_t
*pos
, dompos_t
*new_pos
)
855 dompos_addref(&iter
);
858 if(!find_prev_space(This
, &iter
, FALSE
, &tmp
))
861 dompos_release(&iter
);
870 #define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface)
872 static HRESULT WINAPI
HTMLTxtRange_QueryInterface(IHTMLTxtRange
*iface
, REFIID riid
, void **ppv
)
874 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
878 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
879 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
880 *ppv
= HTMLTXTRANGE(This
);
881 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
882 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
883 *ppv
= HTMLTXTRANGE(This
);
884 }else if(IsEqualGUID(&IID_IHTMLTxtRange
, riid
)) {
885 TRACE("(%p)->(IID_IHTMLTxtRange %p)\n", This
, ppv
);
886 *ppv
= HTMLTXTRANGE(This
);
890 IUnknown_AddRef((IUnknown
*)*ppv
);
894 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
895 return E_NOINTERFACE
;
898 static ULONG WINAPI
HTMLTxtRange_AddRef(IHTMLTxtRange
*iface
)
900 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
901 LONG ref
= InterlockedIncrement(&This
->ref
);
903 TRACE("(%p) ref=%d\n", This
, ref
);
908 static ULONG WINAPI
HTMLTxtRange_Release(IHTMLTxtRange
*iface
)
910 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
911 LONG ref
= InterlockedDecrement(&This
->ref
);
913 TRACE("(%p) ref=%d\n", This
, ref
);
917 nsISelection_Release(This
->nsrange
);
919 list_remove(&This
->entry
);
926 static HRESULT WINAPI
HTMLTxtRange_GetTypeInfoCount(IHTMLTxtRange
*iface
, UINT
*pctinfo
)
928 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
929 FIXME("(%p)->(%p)\n", This
, pctinfo
);
933 static HRESULT WINAPI
HTMLTxtRange_GetTypeInfo(IHTMLTxtRange
*iface
, UINT iTInfo
,
934 LCID lcid
, ITypeInfo
**ppTInfo
)
936 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
937 FIXME("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
941 static HRESULT WINAPI
HTMLTxtRange_GetIDsOfNames(IHTMLTxtRange
*iface
, REFIID riid
,
942 LPOLESTR
*rgszNames
, UINT cNames
,
943 LCID lcid
, DISPID
*rgDispId
)
945 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
946 FIXME("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
951 static HRESULT WINAPI
HTMLTxtRange_Invoke(IHTMLTxtRange
*iface
, DISPID dispIdMember
,
952 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
953 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
955 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
956 FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
957 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
961 static HRESULT WINAPI
HTMLTxtRange_get_htmlText(IHTMLTxtRange
*iface
, BSTR
*p
)
963 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
965 TRACE("(%p)->(%p)\n", This
, p
);
970 nsIDOMDocumentFragment
*fragment
;
973 nsres
= nsIDOMRange_CloneContents(This
->nsrange
, &fragment
);
974 if(NS_SUCCEEDED(nsres
)) {
975 const PRUnichar
*nstext
;
978 nsAString_Init(&nsstr
, NULL
);
979 nsnode_to_nsstring((nsIDOMNode
*)fragment
, &nsstr
);
980 nsIDOMDocumentFragment_Release(fragment
);
982 nsAString_GetData(&nsstr
, &nstext
, NULL
);
983 *p
= SysAllocString(nstext
);
985 nsAString_Finish(&nsstr
);
990 const WCHAR emptyW
[] = {0};
991 *p
= SysAllocString(emptyW
);
994 TRACE("return %s\n", debugstr_w(*p
));
998 static HRESULT WINAPI
HTMLTxtRange_put_text(IHTMLTxtRange
*iface
, BSTR v
)
1000 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1001 nsIDOMDocument
*nsdoc
;
1002 nsIDOMText
*text_node
;
1006 TRACE("(%p)->(%s)\n", This
, debugstr_w(v
));
1009 return MSHTML_E_NODOC
;
1011 nsres
= nsIWebNavigation_GetDocument(This
->doc
->nscontainer
->navigation
, &nsdoc
);
1012 if(NS_FAILED(nsres
)) {
1013 ERR("GetDocument failed: %08x\n", nsres
);
1017 nsAString_Init(&text_str
, v
);
1018 nsres
= nsIDOMDocument_CreateTextNode(nsdoc
, &text_str
, &text_node
);
1019 nsIDOMDocument_Release(nsdoc
);
1020 nsAString_Finish(&text_str
);
1021 if(NS_FAILED(nsres
)) {
1022 ERR("CreateTextNode failed: %08x\n", nsres
);
1025 nsres
= nsIDOMRange_DeleteContents(This
->nsrange
);
1026 if(NS_FAILED(nsres
))
1027 ERR("DeleteContents failed: %08x\n", nsres
);
1029 nsres
= nsIDOMRange_InsertNode(This
->nsrange
, (nsIDOMNode
*)text_node
);
1030 if(NS_FAILED(nsres
))
1031 ERR("InsertNode failed: %08x\n", nsres
);
1033 nsres
= nsIDOMRange_SetEndAfter(This
->nsrange
, (nsIDOMNode
*)text_node
);
1034 if(NS_FAILED(nsres
))
1035 ERR("SetEndAfter failed: %08x\n", nsres
);
1037 return IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), VARIANT_FALSE
);
1040 static HRESULT WINAPI
HTMLTxtRange_get_text(IHTMLTxtRange
*iface
, BSTR
*p
)
1042 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1045 TRACE("(%p)->(%p)\n", This
, p
);
1052 range_to_string(This
, &buf
);
1054 *p
= SysAllocString(buf
.buf
);
1055 wstrbuf_finish(&buf
);
1057 TRACE("ret %s\n", debugstr_w(*p
));
1061 static HRESULT WINAPI
HTMLTxtRange_parentElement(IHTMLTxtRange
*iface
, IHTMLElement
**parent
)
1063 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1064 nsIDOMNode
*nsnode
, *tmp
;
1067 TRACE("(%p)->(%p)\n", This
, parent
);
1069 nsIDOMRange_GetCommonAncestorContainer(This
->nsrange
, &nsnode
);
1070 while(nsnode
&& get_node_type(nsnode
) != ELEMENT_NODE
) {
1071 nsIDOMNode_GetParentNode(nsnode
, &tmp
);
1072 nsIDOMNode_Release(nsnode
);
1081 node
= get_node(This
->doc
, nsnode
);
1082 nsIDOMNode_Release(nsnode
);
1084 return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(node
), &IID_IHTMLElement
, (void**)parent
);
1087 static HRESULT WINAPI
HTMLTxtRange_duplicate(IHTMLTxtRange
*iface
, IHTMLTxtRange
**Duplicate
)
1089 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1090 nsIDOMRange
*nsrange
= NULL
;
1092 TRACE("(%p)->(%p)\n", This
, Duplicate
);
1094 nsIDOMRange_CloneRange(This
->nsrange
, &nsrange
);
1095 *Duplicate
= HTMLTxtRange_Create(This
->doc
, nsrange
);
1096 nsIDOMRange_Release(nsrange
);
1101 static HRESULT WINAPI
HTMLTxtRange_inRange(IHTMLTxtRange
*iface
, IHTMLTxtRange
*Range
,
1102 VARIANT_BOOL
*InRange
)
1104 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1105 HTMLTxtRange
*src_range
;
1109 TRACE("(%p)->(%p %p)\n", This
, Range
, InRange
);
1111 *InRange
= VARIANT_FALSE
;
1113 src_range
= get_range_object(This
->doc
, Range
);
1117 nsres
= nsIDOMRange_CompareBoundaryPoints(This
->nsrange
, NS_START_TO_START
,
1118 src_range
->nsrange
, &nsret
);
1119 if(NS_SUCCEEDED(nsres
) && nsret
<= 0) {
1120 nsres
= nsIDOMRange_CompareBoundaryPoints(This
->nsrange
, NS_END_TO_END
,
1121 src_range
->nsrange
, &nsret
);
1122 if(NS_SUCCEEDED(nsres
) && nsret
>= 0)
1123 *InRange
= VARIANT_TRUE
;
1126 if(NS_FAILED(nsres
))
1127 ERR("CompareBoundaryPoints failed: %08x\n", nsres
);
1132 static HRESULT WINAPI
HTMLTxtRange_isEqual(IHTMLTxtRange
*iface
, IHTMLTxtRange
*Range
,
1133 VARIANT_BOOL
*IsEqual
)
1135 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1136 HTMLTxtRange
*src_range
;
1140 TRACE("(%p)->(%p %p)\n", This
, Range
, IsEqual
);
1142 *IsEqual
= VARIANT_FALSE
;
1144 src_range
= get_range_object(This
->doc
, Range
);
1148 nsres
= nsIDOMRange_CompareBoundaryPoints(This
->nsrange
, NS_START_TO_START
,
1149 src_range
->nsrange
, &nsret
);
1150 if(NS_SUCCEEDED(nsres
) && !nsret
) {
1151 nsres
= nsIDOMRange_CompareBoundaryPoints(This
->nsrange
, NS_END_TO_END
,
1152 src_range
->nsrange
, &nsret
);
1153 if(NS_SUCCEEDED(nsres
) && !nsret
)
1154 *IsEqual
= VARIANT_TRUE
;
1157 if(NS_FAILED(nsres
))
1158 ERR("CompareBoundaryPoints failed: %08x\n", nsres
);
1163 static HRESULT WINAPI
HTMLTxtRange_scrollIntoView(IHTMLTxtRange
*iface
, VARIANT_BOOL fStart
)
1165 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1166 FIXME("(%p)->(%x)\n", This
, fStart
);
1170 static HRESULT WINAPI
HTMLTxtRange_collapse(IHTMLTxtRange
*iface
, VARIANT_BOOL Start
)
1172 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1174 TRACE("(%p)->(%x)\n", This
, Start
);
1176 nsIDOMRange_Collapse(This
->nsrange
, Start
!= VARIANT_FALSE
);
1180 static HRESULT WINAPI
HTMLTxtRange_expand(IHTMLTxtRange
*iface
, BSTR Unit
, VARIANT_BOOL
*Success
)
1182 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1185 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(Unit
), Success
);
1187 unit
= string_to_unit(Unit
);
1188 if(unit
== RU_UNKNOWN
)
1189 return E_INVALIDARG
;
1191 *Success
= VARIANT_FALSE
;
1195 dompos_t end_pos
, start_pos
, new_pos
;
1197 get_cur_pos(This
, TRUE
, &start_pos
);
1198 get_cur_pos(This
, FALSE
, &end_pos
);
1200 if(!isspaceW(get_pos_char(&end_pos
))) {
1201 if(find_next_space(&end_pos
, &new_pos
)) {
1202 set_range_pos(This
, FALSE
, &new_pos
);
1203 *Success
= VARIANT_TRUE
;
1205 dompos_release(&new_pos
);
1208 if(find_prev_space(This
, &start_pos
, TRUE
, &new_pos
)) {
1209 set_range_pos(This
, TRUE
, &new_pos
);
1210 *Success
= VARIANT_TRUE
;
1213 dompos_release(&new_pos
);
1214 dompos_release(&end_pos
);
1220 nsIDOMDocument
*nsdoc
;
1221 nsIDOMHTMLDocument
*nshtmldoc
;
1222 nsIDOMHTMLElement
*nsbody
= NULL
;
1225 nsres
= nsIWebNavigation_GetDocument(This
->doc
->nscontainer
->navigation
, &nsdoc
);
1226 if(NS_FAILED(nsres
) || !nsdoc
) {
1227 ERR("GetDocument failed: %08x\n", nsres
);
1231 nsIDOMDocument_QueryInterface(nsdoc
, &IID_nsIDOMHTMLDocument
, (void**)&nshtmldoc
);
1232 nsIDOMDocument_Release(nsdoc
);
1234 nsres
= nsIDOMHTMLDocument_GetBody(nshtmldoc
, &nsbody
);
1235 nsIDOMHTMLDocument_Release(nshtmldoc
);
1236 if(NS_FAILED(nsres
) || !nsbody
) {
1237 ERR("Could not get body: %08x\n", nsres
);
1241 nsres
= nsIDOMRange_SelectNodeContents(This
->nsrange
, (nsIDOMNode
*)nsbody
);
1242 nsIDOMHTMLElement_Release(nsbody
);
1243 if(NS_FAILED(nsres
)) {
1244 ERR("Collapse failed: %08x\n", nsres
);
1248 *Success
= VARIANT_TRUE
;
1253 FIXME("Unimplemented unit %s\n", debugstr_w(Unit
));
1259 static HRESULT WINAPI
HTMLTxtRange_move(IHTMLTxtRange
*iface
, BSTR Unit
,
1260 long Count
, long *ActualCount
)
1262 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1265 TRACE("(%p)->(%s %ld %p)\n", This
, debugstr_w(Unit
), Count
, ActualCount
);
1267 unit
= string_to_unit(Unit
);
1268 if(unit
== RU_UNKNOWN
)
1269 return E_INVALIDARG
;
1271 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), TRUE
);
1280 dompos_t cur_pos
, new_pos
;
1282 get_cur_pos(This
, TRUE
, &cur_pos
);
1285 *ActualCount
= move_next_chars(Count
, &cur_pos
, TRUE
, NULL
, NULL
, &new_pos
);
1286 set_range_pos(This
, FALSE
, &new_pos
);
1287 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), FALSE
);
1288 dompos_release(&new_pos
);
1290 *ActualCount
= -move_prev_chars(This
, -Count
, &cur_pos
, FALSE
, NULL
, NULL
, &new_pos
);
1291 set_range_pos(This
, TRUE
, &new_pos
);
1292 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), TRUE
);
1293 dompos_release(&new_pos
);
1296 dompos_release(&cur_pos
);
1301 dompos_t cur_pos
, new_pos
;
1303 get_cur_pos(This
, TRUE
, &cur_pos
);
1306 *ActualCount
= move_next_words(Count
, &cur_pos
, &new_pos
);
1307 set_range_pos(This
, FALSE
, &new_pos
);
1308 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), FALSE
);
1309 dompos_release(&new_pos
);
1311 *ActualCount
= -move_prev_words(This
, -Count
, &cur_pos
, &new_pos
);
1312 set_range_pos(This
, TRUE
, &new_pos
);
1313 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), TRUE
);
1314 dompos_release(&new_pos
);
1317 dompos_release(&cur_pos
);
1322 FIXME("unimplemented unit %s\n", debugstr_w(Unit
));
1325 TRACE("ret %ld\n", *ActualCount
);
1329 static HRESULT WINAPI
HTMLTxtRange_moveStart(IHTMLTxtRange
*iface
, BSTR Unit
,
1330 long Count
, long *ActualCount
)
1332 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1335 TRACE("(%p)->(%s %ld %p)\n", This
, debugstr_w(Unit
), Count
, ActualCount
);
1337 unit
= string_to_unit(Unit
);
1338 if(unit
== RU_UNKNOWN
)
1339 return E_INVALIDARG
;
1348 dompos_t start_pos
, end_pos
, new_pos
;
1351 get_cur_pos(This
, TRUE
, &start_pos
);
1352 get_cur_pos(This
, FALSE
, &end_pos
);
1353 nsIDOMRange_GetCollapsed(This
->nsrange
, &collapsed
);
1358 *ActualCount
= move_next_chars(Count
, &start_pos
, collapsed
, &end_pos
, &bounded
, &new_pos
);
1359 set_range_pos(This
, !bounded
, &new_pos
);
1361 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), FALSE
);
1363 *ActualCount
= -move_prev_chars(This
, -Count
, &start_pos
, FALSE
, NULL
, NULL
, &new_pos
);
1364 set_range_pos(This
, TRUE
, &new_pos
);
1367 dompos_release(&start_pos
);
1368 dompos_release(&end_pos
);
1369 dompos_release(&new_pos
);
1374 FIXME("unimplemented unit %s\n", debugstr_w(Unit
));
1380 static HRESULT WINAPI
HTMLTxtRange_moveEnd(IHTMLTxtRange
*iface
, BSTR Unit
,
1381 long Count
, long *ActualCount
)
1383 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1386 TRACE("(%p)->(%s %ld %p)\n", This
, debugstr_w(Unit
), Count
, ActualCount
);
1388 unit
= string_to_unit(Unit
);
1389 if(unit
== RU_UNKNOWN
)
1390 return E_INVALIDARG
;
1399 dompos_t start_pos
, end_pos
, new_pos
;
1402 get_cur_pos(This
, TRUE
, &start_pos
);
1403 get_cur_pos(This
, FALSE
, &end_pos
);
1404 nsIDOMRange_GetCollapsed(This
->nsrange
, &collapsed
);
1407 *ActualCount
= move_next_chars(Count
, &end_pos
, collapsed
, NULL
, NULL
, &new_pos
);
1408 set_range_pos(This
, FALSE
, &new_pos
);
1412 *ActualCount
= -move_prev_chars(This
, -Count
, &end_pos
, TRUE
, &start_pos
, &bounded
, &new_pos
);
1413 set_range_pos(This
, bounded
, &new_pos
);
1415 IHTMLTxtRange_collapse(HTMLTXTRANGE(This
), TRUE
);
1418 dompos_release(&start_pos
);
1419 dompos_release(&end_pos
);
1420 dompos_release(&new_pos
);
1425 FIXME("unimplemented unit %s\n", debugstr_w(Unit
));
1431 static HRESULT WINAPI
HTMLTxtRange_select(IHTMLTxtRange
*iface
)
1433 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1435 TRACE("(%p)\n", This
);
1437 if(This
->doc
->nscontainer
) {
1438 nsIDOMWindow
*dom_window
= NULL
;
1439 nsISelection
*nsselection
;
1441 nsIWebBrowser_GetContentDOMWindow(This
->doc
->nscontainer
->webbrowser
, &dom_window
);
1442 nsIDOMWindow_GetSelection(dom_window
, &nsselection
);
1443 nsIDOMWindow_Release(dom_window
);
1445 nsISelection_RemoveAllRanges(nsselection
);
1446 nsISelection_AddRange(nsselection
, This
->nsrange
);
1448 nsISelection_Release(nsselection
);
1454 static HRESULT WINAPI
HTMLTxtRange_pasteHTML(IHTMLTxtRange
*iface
, BSTR html
)
1456 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1457 FIXME("(%p)->(%s)\n", This
, debugstr_w(html
));
1461 static HRESULT WINAPI
HTMLTxtRange_moveToElementText(IHTMLTxtRange
*iface
, IHTMLElement
*element
)
1463 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1464 FIXME("(%p)->(%p)\n", This
, element
);
1468 static HRESULT WINAPI
HTMLTxtRange_setEndPoint(IHTMLTxtRange
*iface
, BSTR how
,
1469 IHTMLTxtRange
*SourceRange
)
1471 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1472 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(how
), SourceRange
);
1476 static HRESULT WINAPI
HTMLTxtRange_compareEndPoints(IHTMLTxtRange
*iface
, BSTR how
,
1477 IHTMLTxtRange
*SourceRange
, long *ret
)
1479 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1480 HTMLTxtRange
*src_range
;
1485 TRACE("(%p)->(%s %p %p)\n", This
, debugstr_w(how
), SourceRange
, ret
);
1487 nscmpt
= string_to_nscmptype(how
);
1489 return E_INVALIDARG
;
1491 src_range
= get_range_object(This
->doc
, SourceRange
);
1495 nsres
= nsIDOMRange_CompareBoundaryPoints(This
->nsrange
, nscmpt
, src_range
->nsrange
, &nsret
);
1496 if(NS_FAILED(nsres
))
1497 ERR("CompareBoundaryPoints failed: %08x\n", nsres
);
1503 static HRESULT WINAPI
HTMLTxtRange_findText(IHTMLTxtRange
*iface
, BSTR String
,
1504 long count
, long Flags
, VARIANT_BOOL
*Success
)
1506 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1507 FIXME("(%p)->(%s %ld %08lx %p)\n", This
, debugstr_w(String
), count
, Flags
, Success
);
1511 static HRESULT WINAPI
HTMLTxtRange_moveToPoint(IHTMLTxtRange
*iface
, long x
, long y
)
1513 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1514 FIXME("(%p)->(%ld %ld)\n", This
, x
, y
);
1518 static HRESULT WINAPI
HTMLTxtRange_getBookmark(IHTMLTxtRange
*iface
, BSTR
*Bookmark
)
1520 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1521 FIXME("(%p)->(%p)\n", This
, Bookmark
);
1525 static HRESULT WINAPI
HTMLTxtRange_moveToBookmark(IHTMLTxtRange
*iface
, BSTR Bookmark
,
1526 VARIANT_BOOL
*Success
)
1528 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1529 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(Bookmark
), Success
);
1533 static HRESULT WINAPI
HTMLTxtRange_queryCommandSupported(IHTMLTxtRange
*iface
, BSTR cmdID
,
1534 VARIANT_BOOL
*pfRet
)
1536 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1537 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pfRet
);
1541 static HRESULT WINAPI
HTMLTxtRange_queryCommandEnabled(IHTMLTxtRange
*iface
, BSTR cmdID
,
1542 VARIANT_BOOL
*pfRet
)
1544 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1545 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pfRet
);
1549 static HRESULT WINAPI
HTMLTxtRange_queryCommandState(IHTMLTxtRange
*iface
, BSTR cmdID
,
1550 VARIANT_BOOL
*pfRet
)
1552 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1553 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pfRet
);
1557 static HRESULT WINAPI
HTMLTxtRange_queryCommandIndeterm(IHTMLTxtRange
*iface
, BSTR cmdID
,
1558 VARIANT_BOOL
*pfRet
)
1560 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1561 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pfRet
);
1565 static HRESULT WINAPI
HTMLTxtRange_queryCommandText(IHTMLTxtRange
*iface
, BSTR cmdID
,
1568 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1569 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pcmdText
);
1573 static HRESULT WINAPI
HTMLTxtRange_queryCommandValue(IHTMLTxtRange
*iface
, BSTR cmdID
,
1576 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1577 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pcmdValue
);
1581 static HRESULT WINAPI
HTMLTxtRange_execCommand(IHTMLTxtRange
*iface
, BSTR cmdID
,
1582 VARIANT_BOOL showUI
, VARIANT value
, VARIANT_BOOL
*pfRet
)
1584 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1585 FIXME("(%p)->(%s %x v %p)\n", This
, debugstr_w(cmdID
), showUI
, pfRet
);
1589 static HRESULT WINAPI
HTMLTxtRange_execCommandShowHelp(IHTMLTxtRange
*iface
, BSTR cmdID
,
1590 VARIANT_BOOL
*pfRet
)
1592 HTMLTxtRange
*This
= HTMLTXTRANGE_THIS(iface
);
1593 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(cmdID
), pfRet
);
1597 #undef HTMLTXTRANGE_THIS
1599 static const IHTMLTxtRangeVtbl HTMLTxtRangeVtbl
= {
1600 HTMLTxtRange_QueryInterface
,
1601 HTMLTxtRange_AddRef
,
1602 HTMLTxtRange_Release
,
1603 HTMLTxtRange_GetTypeInfoCount
,
1604 HTMLTxtRange_GetTypeInfo
,
1605 HTMLTxtRange_GetIDsOfNames
,
1606 HTMLTxtRange_Invoke
,
1607 HTMLTxtRange_get_htmlText
,
1608 HTMLTxtRange_put_text
,
1609 HTMLTxtRange_get_text
,
1610 HTMLTxtRange_parentElement
,
1611 HTMLTxtRange_duplicate
,
1612 HTMLTxtRange_inRange
,
1613 HTMLTxtRange_isEqual
,
1614 HTMLTxtRange_scrollIntoView
,
1615 HTMLTxtRange_collapse
,
1616 HTMLTxtRange_expand
,
1618 HTMLTxtRange_moveStart
,
1619 HTMLTxtRange_moveEnd
,
1620 HTMLTxtRange_select
,
1621 HTMLTxtRange_pasteHTML
,
1622 HTMLTxtRange_moveToElementText
,
1623 HTMLTxtRange_setEndPoint
,
1624 HTMLTxtRange_compareEndPoints
,
1625 HTMLTxtRange_findText
,
1626 HTMLTxtRange_moveToPoint
,
1627 HTMLTxtRange_getBookmark
,
1628 HTMLTxtRange_moveToBookmark
,
1629 HTMLTxtRange_queryCommandSupported
,
1630 HTMLTxtRange_queryCommandEnabled
,
1631 HTMLTxtRange_queryCommandState
,
1632 HTMLTxtRange_queryCommandIndeterm
,
1633 HTMLTxtRange_queryCommandText
,
1634 HTMLTxtRange_queryCommandValue
,
1635 HTMLTxtRange_execCommand
,
1636 HTMLTxtRange_execCommandShowHelp
1639 IHTMLTxtRange
*HTMLTxtRange_Create(HTMLDocument
*doc
, nsIDOMRange
*nsrange
)
1641 HTMLTxtRange
*ret
= mshtml_alloc(sizeof(HTMLTxtRange
));
1643 ret
->lpHTMLTxtRangeVtbl
= &HTMLTxtRangeVtbl
;
1647 nsIDOMRange_AddRef(nsrange
);
1648 ret
->nsrange
= nsrange
;
1651 list_add_head(&doc
->range_list
, &ret
->entry
);
1653 return HTMLTXTRANGE(ret
);
1656 void detach_ranges(HTMLDocument
*This
)
1660 LIST_FOR_EACH_ENTRY(iter
, &This
->range_list
, HTMLTxtRange
, entry
) {