widl: Allow size_is on strings.
[wine] / dlls / mshtml / txtrange.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 #include "mshtml_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
38
39 typedef struct {
40     const IHTMLTxtRangeVtbl *lpHTMLTxtRangeVtbl;
41
42     LONG ref;
43
44     nsIDOMRange *nsrange;
45     HTMLDocument *doc;
46
47     struct list entry;
48 } HTMLTxtRange;
49
50 #define HTMLTXTRANGE(x)  ((IHTMLTxtRange*)  &(x)->lpHTMLTxtRangeVtbl)
51
52 static HTMLTxtRange *get_range_object(HTMLDocument *doc, IHTMLTxtRange *iface)
53 {
54     HTMLTxtRange *iter;
55
56     LIST_FOR_EACH_ENTRY(iter, &doc->range_list, HTMLTxtRange, entry) {
57         if(HTMLTXTRANGE(iter) == iface)
58             return iter;
59     }
60
61     ERR("Could not find range in document\n");
62     return NULL;
63 }
64
65 static int string_to_nscmptype(LPCWSTR str)
66 {
67     static const WCHAR seW[] = {'S','t','a','r','t','T','o','E','n','d',0};
68     static const WCHAR ssW[] = {'S','t','a','r','t','T','o','S','t','a','r','t',0};
69     static const WCHAR esW[] = {'E','n','d','T','o','S','t','a','r','t',0};
70     static const WCHAR eeW[] = {'E','n','d','T','o','E','n','d',0};
71
72     if(!strcmpiW(str, seW))  return NS_START_TO_END;
73     if(!strcmpiW(str, ssW))  return NS_START_TO_START;
74     if(!strcmpiW(str, esW))  return NS_END_TO_START;
75     if(!strcmpiW(str, eeW))  return NS_END_TO_END;
76
77     return -1;
78 }
79
80 #define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface)
81
82 static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv)
83 {
84     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
85
86     *ppv = NULL;
87
88     if(IsEqualGUID(&IID_IUnknown, riid)) {
89         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
90         *ppv = HTMLTXTRANGE(This);
91     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
92         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
93         *ppv = HTMLTXTRANGE(This);
94     }else if(IsEqualGUID(&IID_IHTMLTxtRange, riid)) {
95         TRACE("(%p)->(IID_IHTMLTxtRange %p)\n", This, ppv);
96         *ppv = HTMLTXTRANGE(This);
97     }
98
99     if(*ppv) {
100         IUnknown_AddRef((IUnknown*)*ppv);
101         return S_OK;
102     }
103
104     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
105     return E_NOINTERFACE;
106 }
107
108 static ULONG WINAPI HTMLTxtRange_AddRef(IHTMLTxtRange *iface)
109 {
110     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
111     LONG ref = InterlockedIncrement(&This->ref);
112
113     TRACE("(%p) ref=%d\n", This, ref);
114
115     return ref;
116 }
117
118 static ULONG WINAPI HTMLTxtRange_Release(IHTMLTxtRange *iface)
119 {
120     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
121     LONG ref = InterlockedDecrement(&This->ref);
122
123     TRACE("(%p) ref=%d\n", This, ref);
124
125     if(!ref) {
126         if(This->nsrange)
127             nsISelection_Release(This->nsrange);
128         if(This->doc)
129             list_remove(&This->entry);
130         mshtml_free(This);
131     }
132
133     return ref;
134 }
135
136 static HRESULT WINAPI HTMLTxtRange_GetTypeInfoCount(IHTMLTxtRange *iface, UINT *pctinfo)
137 {
138     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
139     FIXME("(%p)->(%p)\n", This, pctinfo);
140     return E_NOTIMPL;
141 }
142
143 static HRESULT WINAPI HTMLTxtRange_GetTypeInfo(IHTMLTxtRange *iface, UINT iTInfo,
144                                                LCID lcid, ITypeInfo **ppTInfo)
145 {
146     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
147     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
148     return E_NOTIMPL;
149 }
150
151 static HRESULT WINAPI HTMLTxtRange_GetIDsOfNames(IHTMLTxtRange *iface, REFIID riid,
152                                                  LPOLESTR *rgszNames, UINT cNames,
153                                                  LCID lcid, DISPID *rgDispId)
154 {
155     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
156     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
157           lcid, rgDispId);
158     return E_NOTIMPL;
159 }
160
161 static HRESULT WINAPI HTMLTxtRange_Invoke(IHTMLTxtRange *iface, DISPID dispIdMember,
162                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
163                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
164 {
165     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
166     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
167           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
168     return E_NOTIMPL;
169 }
170
171 static HRESULT WINAPI HTMLTxtRange_get_htmlText(IHTMLTxtRange *iface, BSTR *p)
172 {
173     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
174
175     TRACE("(%p)->(%p)\n", This, p);
176
177     *p = NULL;
178
179     if(This->nsrange) {
180         nsIDOMDocumentFragment *fragment;
181         nsresult nsres;
182
183         nsres = nsIDOMRange_CloneContents(This->nsrange, &fragment);
184         if(NS_SUCCEEDED(nsres)) {
185             const PRUnichar *nstext;
186             nsAString nsstr;
187
188             nsAString_Init(&nsstr, NULL);
189             nsnode_to_nsstring((nsIDOMNode*)fragment, &nsstr);
190             nsIDOMDocumentFragment_Release(fragment);
191
192             nsAString_GetData(&nsstr, &nstext, NULL);
193             *p = SysAllocString(nstext);
194
195             nsAString_Finish(&nsstr);
196         }
197     }
198
199     if(!*p) {
200         const WCHAR emptyW[] = {0};
201         *p = SysAllocString(emptyW);
202     }
203
204     TRACE("return %s\n", debugstr_w(*p));
205     return S_OK;
206 }
207
208 static HRESULT WINAPI HTMLTxtRange_put_text(IHTMLTxtRange *iface, BSTR v)
209 {
210     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
211     nsIDOMDocument *nsdoc;
212     nsIDOMText *text_node;
213     nsAString text_str;
214     nsresult nsres;
215
216     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
217
218     if(!This->doc)
219         return MSHTML_E_NODOC;
220
221     nsres = nsIWebNavigation_GetDocument(This->doc->nscontainer->navigation, &nsdoc);
222     if(NS_FAILED(nsres)) {
223         ERR("GetDocument failed: %08x\n", nsres);
224         return S_OK;
225     }
226
227     nsAString_Init(&text_str, v);
228     nsres = nsIDOMDocument_CreateTextNode(nsdoc, &text_str, &text_node);
229     nsAString_Finish(&text_str);
230     if(NS_FAILED(nsres)) {
231         ERR("CreateTextNode failed: %08x\n", nsres);
232         return S_OK;
233     }
234     nsres = nsIDOMRange_DeleteContents(This->nsrange);
235     if(NS_FAILED(nsres))
236         ERR("DeleteContents failed: %08x\n", nsres);
237
238     nsres = nsIDOMRange_InsertNode(This->nsrange, (nsIDOMNode*)text_node);
239     if(NS_FAILED(nsres))
240         ERR("InsertNode failed: %08x\n", nsres);
241
242     return S_OK;
243 }
244
245 static HRESULT WINAPI HTMLTxtRange_get_text(IHTMLTxtRange *iface, BSTR *p)
246 {
247     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
248
249     TRACE("(%p)->(%p)\n", This, p);
250
251     *p = NULL;
252
253     if(This->nsrange) {
254         nsAString text_str;
255         nsresult nsres;
256
257         nsAString_Init(&text_str, NULL);
258
259         nsres = nsIDOMRange_ToString(This->nsrange, &text_str);
260         if(NS_SUCCEEDED(nsres)) {
261             const PRUnichar *nstext;
262
263             nsAString_GetData(&text_str, &nstext, NULL);
264             *p = SysAllocString(nstext);
265         }else {
266             ERR("ToString failed: %08x\n", nsres);
267         }
268
269         nsAString_Finish(&text_str);
270     }
271
272     if(!*p) {
273         static const WCHAR empty[] = {0};
274         *p = SysAllocString(empty);
275     }
276
277     return S_OK;
278 }
279
280 static HRESULT WINAPI HTMLTxtRange_parentElement(IHTMLTxtRange *iface, IHTMLElement **parent)
281 {
282     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
283     FIXME("(%p)->(%p)\n", This, parent);
284     return E_NOTIMPL;
285 }
286
287 static HRESULT WINAPI HTMLTxtRange_duplicate(IHTMLTxtRange *iface, IHTMLTxtRange **Duplicate)
288 {
289     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
290     nsIDOMRange *nsrange = NULL;
291
292     TRACE("(%p)->(%p)\n", This, Duplicate);
293
294     nsIDOMRange_CloneRange(This->nsrange, &nsrange);
295     *Duplicate = HTMLTxtRange_Create(This->doc, nsrange);
296     nsIDOMRange_Release(nsrange);
297
298     return S_OK;
299 }
300
301 static HRESULT WINAPI HTMLTxtRange_inRange(IHTMLTxtRange *iface, IHTMLTxtRange *Range,
302         VARIANT_BOOL *InRange)
303 {
304     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
305     FIXME("(%p)->(%p %p)\n", This, Range, InRange);
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI HTMLTxtRange_isEqual(IHTMLTxtRange *iface, IHTMLTxtRange *Range,
310         VARIANT_BOOL *IsEqual)
311 {
312     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
313     FIXME("(%p)->(%p %p)\n", This, Range, IsEqual);
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI HTMLTxtRange_scrollIntoView(IHTMLTxtRange *iface, VARIANT_BOOL fStart)
318 {
319     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
320     FIXME("(%p)->(%x)\n", This, fStart);
321     return E_NOTIMPL;
322 }
323
324 static HRESULT WINAPI HTMLTxtRange_collapse(IHTMLTxtRange *iface, VARIANT_BOOL Start)
325 {
326     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
327
328     TRACE("(%p)->(%x)\n", This, Start);
329
330     nsIDOMRange_Collapse(This->nsrange, Start != VARIANT_FALSE);
331     return S_OK;
332 }
333
334 static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIANT_BOOL *Success)
335 {
336     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
337     FIXME("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success);
338     return E_NOTIMPL;
339 }
340
341 static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit,
342         long Count, long *ActualCount)
343 {
344     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
345     FIXME("(%p)->(%s %ld %p)\n", This, debugstr_w(Unit), Count, ActualCount);
346     return E_NOTIMPL;
347 }
348
349 static HRESULT WINAPI HTMLTxtRange_moveStart(IHTMLTxtRange *iface, BSTR Unit,
350         long Count, long *ActualCount)
351 {
352     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
353     FIXME("(%p)->(%s %ld %p)\n", This, debugstr_w(Unit), Count, ActualCount);
354     return E_NOTIMPL;
355 }
356
357 static HRESULT WINAPI HTMLTxtRange_moveEnd(IHTMLTxtRange *iface, BSTR Unit,
358         long Count, long *ActualCount)
359 {
360     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
361     FIXME("(%p)->(%s %ld %p)\n", This, debugstr_w(Unit), Count, ActualCount);
362     return E_NOTIMPL;
363 }
364
365 static HRESULT WINAPI HTMLTxtRange_select(IHTMLTxtRange *iface)
366 {
367     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
368
369     TRACE("(%p)\n", This);
370
371     if(This->doc->nscontainer) {
372         nsIDOMWindow *dom_window = NULL;
373         nsISelection *nsselection;
374
375         nsIWebBrowser_GetContentDOMWindow(This->doc->nscontainer->webbrowser, &dom_window);
376         nsIDOMWindow_GetSelection(dom_window, &nsselection);
377         nsIDOMWindow_Release(dom_window);
378
379         nsISelection_RemoveAllRanges(nsselection);
380         nsISelection_AddRange(nsselection, This->nsrange);
381
382         nsISelection_Release(nsselection);
383     }
384
385     return S_OK;
386 }
387
388 static HRESULT WINAPI HTMLTxtRange_pasteHTML(IHTMLTxtRange *iface, BSTR html)
389 {
390     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
391     FIXME("(%p)->(%s)\n", This, debugstr_w(html));
392     return E_NOTIMPL;
393 }
394
395 static HRESULT WINAPI HTMLTxtRange_moveToElementText(IHTMLTxtRange *iface, IHTMLElement *element)
396 {
397     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
398     FIXME("(%p)->(%p)\n", This, element);
399     return E_NOTIMPL;
400 }
401
402 static HRESULT WINAPI HTMLTxtRange_setEndPoint(IHTMLTxtRange *iface, BSTR how,
403         IHTMLTxtRange *SourceRange)
404 {
405     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
406     FIXME("(%p)->(%s %p)\n", This, debugstr_w(how), SourceRange);
407     return E_NOTIMPL;
408 }
409
410 static HRESULT WINAPI HTMLTxtRange_compareEndPoints(IHTMLTxtRange *iface, BSTR how,
411         IHTMLTxtRange *SourceRange, long *ret)
412 {
413     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
414     HTMLTxtRange *src_range;
415     PRInt16 nsret = 0;
416     int nscmpt;
417     nsresult nsres;
418
419     TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(how), SourceRange, ret);
420
421     nscmpt = string_to_nscmptype(how);
422     if(nscmpt == -1)
423         return E_INVALIDARG;
424
425     src_range = get_range_object(This->doc, SourceRange);
426     if(!src_range)
427         return E_FAIL;
428
429     nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, nscmpt, src_range->nsrange, &nsret);
430     if(NS_FAILED(nsres))
431         ERR("CompareBoundaryPoints failed: %08x\n", nsres);
432
433     *ret = nsret;
434     return S_OK;
435 }
436
437 static HRESULT WINAPI HTMLTxtRange_findText(IHTMLTxtRange *iface, BSTR String,
438         long count, long Flags, VARIANT_BOOL *Success)
439 {
440     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
441     FIXME("(%p)->(%s %ld %08lx %p)\n", This, debugstr_w(String), count, Flags, Success);
442     return E_NOTIMPL;
443 }
444
445 static HRESULT WINAPI HTMLTxtRange_moveToPoint(IHTMLTxtRange *iface, long x, long y)
446 {
447     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
448     FIXME("(%p)->(%ld %ld)\n", This, x, y);
449     return E_NOTIMPL;
450 }
451
452 static HRESULT WINAPI HTMLTxtRange_getBookmark(IHTMLTxtRange *iface, BSTR *Bookmark)
453 {
454     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
455     FIXME("(%p)->(%p)\n", This, Bookmark);
456     return E_NOTIMPL;
457 }
458
459 static HRESULT WINAPI HTMLTxtRange_moveToBookmark(IHTMLTxtRange *iface, BSTR Bookmark,
460         VARIANT_BOOL *Success)
461 {
462     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
463     FIXME("(%p)->(%s %p)\n", This, debugstr_w(Bookmark), Success);
464     return E_NOTIMPL;
465 }
466
467 static HRESULT WINAPI HTMLTxtRange_queryCommandSupported(IHTMLTxtRange *iface, BSTR cmdID,
468         VARIANT_BOOL *pfRet)
469 {
470     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
471     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
472     return E_NOTIMPL;
473 }
474
475 static HRESULT WINAPI HTMLTxtRange_queryCommandEnabled(IHTMLTxtRange *iface, BSTR cmdID,
476         VARIANT_BOOL *pfRet)
477 {
478     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
479     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
480     return E_NOTIMPL;
481 }
482
483 static HRESULT WINAPI HTMLTxtRange_queryCommandState(IHTMLTxtRange *iface, BSTR cmdID,
484         VARIANT_BOOL *pfRet)
485 {
486     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
487     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI HTMLTxtRange_queryCommandIndeterm(IHTMLTxtRange *iface, BSTR cmdID,
492         VARIANT_BOOL *pfRet)
493 {
494     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
495     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI HTMLTxtRange_queryCommandText(IHTMLTxtRange *iface, BSTR cmdID,
500         BSTR *pcmdText)
501 {
502     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
503     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdText);
504     return E_NOTIMPL;
505 }
506
507 static HRESULT WINAPI HTMLTxtRange_queryCommandValue(IHTMLTxtRange *iface, BSTR cmdID,
508         VARIANT *pcmdValue)
509 {
510     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
511     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdValue);
512     return E_NOTIMPL;
513 }
514
515 static HRESULT WINAPI HTMLTxtRange_execCommand(IHTMLTxtRange *iface, BSTR cmdID,
516         VARIANT_BOOL showUI, VARIANT value, VARIANT_BOOL *pfRet)
517 {
518     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
519     FIXME("(%p)->(%s %x v %p)\n", This, debugstr_w(cmdID), showUI, pfRet);
520     return E_NOTIMPL;
521 }
522
523 static HRESULT WINAPI HTMLTxtRange_execCommandShowHelp(IHTMLTxtRange *iface, BSTR cmdID,
524         VARIANT_BOOL *pfRet)
525 {
526     HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface);
527     FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet);
528     return E_NOTIMPL;
529 }
530
531 #undef HTMLTXTRANGE_THIS
532
533 static const IHTMLTxtRangeVtbl HTMLTxtRangeVtbl = {
534     HTMLTxtRange_QueryInterface,
535     HTMLTxtRange_AddRef,
536     HTMLTxtRange_Release,
537     HTMLTxtRange_GetTypeInfoCount,
538     HTMLTxtRange_GetTypeInfo,
539     HTMLTxtRange_GetIDsOfNames,
540     HTMLTxtRange_Invoke,
541     HTMLTxtRange_get_htmlText,
542     HTMLTxtRange_put_text,
543     HTMLTxtRange_get_text,
544     HTMLTxtRange_parentElement,
545     HTMLTxtRange_duplicate,
546     HTMLTxtRange_inRange,
547     HTMLTxtRange_isEqual,
548     HTMLTxtRange_scrollIntoView,
549     HTMLTxtRange_collapse,
550     HTMLTxtRange_expand,
551     HTMLTxtRange_move,
552     HTMLTxtRange_moveStart,
553     HTMLTxtRange_moveEnd,
554     HTMLTxtRange_select,
555     HTMLTxtRange_pasteHTML,
556     HTMLTxtRange_moveToElementText,
557     HTMLTxtRange_setEndPoint,
558     HTMLTxtRange_compareEndPoints,
559     HTMLTxtRange_findText,
560     HTMLTxtRange_moveToPoint,
561     HTMLTxtRange_getBookmark,
562     HTMLTxtRange_moveToBookmark,
563     HTMLTxtRange_queryCommandSupported,
564     HTMLTxtRange_queryCommandEnabled,
565     HTMLTxtRange_queryCommandState,
566     HTMLTxtRange_queryCommandIndeterm,
567     HTMLTxtRange_queryCommandText,
568     HTMLTxtRange_queryCommandValue,
569     HTMLTxtRange_execCommand,
570     HTMLTxtRange_execCommandShowHelp
571 };
572
573 IHTMLTxtRange *HTMLTxtRange_Create(HTMLDocument *doc, nsIDOMRange *nsrange)
574 {
575     HTMLTxtRange *ret = mshtml_alloc(sizeof(HTMLTxtRange));
576
577     ret->lpHTMLTxtRangeVtbl = &HTMLTxtRangeVtbl;
578     ret->ref = 1;
579
580     if(nsrange)
581         nsIDOMRange_AddRef(nsrange);
582     ret->nsrange = nsrange;
583
584     ret->doc = doc;
585     list_add_head(&doc->range_list, &ret->entry);
586
587     return HTMLTXTRANGE(ret);
588 }
589
590 void detach_ranges(HTMLDocument *This)
591 {
592     HTMLTxtRange *iter;
593
594     LIST_FOR_EACH_ENTRY(iter, &This->range_list, HTMLTxtRange, entry) {
595         iter->doc = NULL;
596     }
597 }