xref: /reactos/dll/win32/mshtml/selection.c (revision 4561998a)
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 "mshtml_private.h"
20 
21 typedef struct {
22     DispatchEx dispex;
23     IHTMLSelectionObject IHTMLSelectionObject_iface;
24     IHTMLSelectionObject2 IHTMLSelectionObject2_iface;
25 
26     LONG ref;
27 
28     nsISelection *nsselection;
29     HTMLDocumentNode *doc;
30 
31     struct list entry;
32 } HTMLSelectionObject;
33 
34 static inline HTMLSelectionObject *impl_from_IHTMLSelectionObject(IHTMLSelectionObject *iface)
35 {
36     return CONTAINING_RECORD(iface, HTMLSelectionObject, IHTMLSelectionObject_iface);
37 }
38 
39 static HRESULT WINAPI HTMLSelectionObject_QueryInterface(IHTMLSelectionObject *iface,
40                                                          REFIID riid, void **ppv)
41 {
42     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
43 
44     TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
45 
46     if(IsEqualGUID(&IID_IUnknown, riid)) {
47         *ppv = &This->IHTMLSelectionObject_iface;
48     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
49         *ppv = &This->IHTMLSelectionObject_iface;
50     }else if(IsEqualGUID(&IID_IHTMLSelectionObject, riid)) {
51         *ppv = &This->IHTMLSelectionObject_iface;
52     }else if(IsEqualGUID(&IID_IHTMLSelectionObject2, riid)) {
53         *ppv = &This->IHTMLSelectionObject2_iface;
54     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
55         return *ppv ? S_OK : E_NOINTERFACE;
56     }else {
57         *ppv = NULL;
58         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
59         return E_NOINTERFACE;
60     }
61 
62     IUnknown_AddRef((IUnknown*)*ppv);
63     return S_OK;
64 }
65 
66 static ULONG WINAPI HTMLSelectionObject_AddRef(IHTMLSelectionObject *iface)
67 {
68     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
69     LONG ref = InterlockedIncrement(&This->ref);
70 
71     TRACE("(%p) ref=%d\n", This, ref);
72 
73     return ref;
74 }
75 
76 static ULONG WINAPI HTMLSelectionObject_Release(IHTMLSelectionObject *iface)
77 {
78     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
79     LONG ref = InterlockedDecrement(&This->ref);
80 
81     TRACE("(%p) ref=%d\n", This, ref);
82 
83     if(!ref) {
84         if(This->nsselection)
85             nsISelection_Release(This->nsselection);
86         if(This->doc)
87             list_remove(&This->entry);
88         release_dispex(&This->dispex);
89         heap_free(This);
90     }
91 
92     return ref;
93 }
94 
95 static HRESULT WINAPI HTMLSelectionObject_GetTypeInfoCount(IHTMLSelectionObject *iface, UINT *pctinfo)
96 {
97     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
98 
99     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
100 }
101 
102 static HRESULT WINAPI HTMLSelectionObject_GetTypeInfo(IHTMLSelectionObject *iface, UINT iTInfo,
103                                               LCID lcid, ITypeInfo **ppTInfo)
104 {
105     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
106 
107     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
108 }
109 
110 static HRESULT WINAPI HTMLSelectionObject_GetIDsOfNames(IHTMLSelectionObject *iface, REFIID riid,
111                                                 LPOLESTR *rgszNames, UINT cNames,
112                                                 LCID lcid, DISPID *rgDispId)
113 {
114     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
115 
116     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames,
117             cNames, lcid, rgDispId);
118 }
119 
120 static HRESULT WINAPI HTMLSelectionObject_Invoke(IHTMLSelectionObject *iface, DISPID dispIdMember,
121                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
122                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
123 {
124     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
125 
126 
127     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid,
128             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
129 }
130 
131 static HRESULT WINAPI HTMLSelectionObject_createRange(IHTMLSelectionObject *iface, IDispatch **range)
132 {
133     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
134     IHTMLTxtRange *range_obj = NULL;
135     nsIDOMRange *nsrange = NULL;
136     HRESULT hres;
137 
138     TRACE("(%p)->(%p)\n", This, range);
139 
140     if(This->nsselection) {
141         LONG nsrange_cnt = 0;
142         nsresult nsres;
143 
144         nsISelection_GetRangeCount(This->nsselection, &nsrange_cnt);
145         if(!nsrange_cnt) {
146             nsIDOMHTMLElement *nsbody = NULL;
147 
148             TRACE("nsrange_cnt = 0\n");
149 
150             if(!This->doc->nsdoc) {
151                 WARN("nsdoc is NULL\n");
152                 return E_UNEXPECTED;
153             }
154 
155             nsres = nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nsbody);
156             if(NS_FAILED(nsres) || !nsbody) {
157                 ERR("Could not get body: %08x\n", nsres);
158                 return E_FAIL;
159             }
160 
161             nsres = nsISelection_Collapse(This->nsselection, (nsIDOMNode*)nsbody, 0);
162             nsIDOMHTMLElement_Release(nsbody);
163             if(NS_FAILED(nsres))
164                 ERR("Collapse failed: %08x\n", nsres);
165         }else if(nsrange_cnt > 1) {
166             FIXME("range_cnt = %d\n", nsrange_cnt);
167         }
168 
169         nsres = nsISelection_GetRangeAt(This->nsselection, 0, &nsrange);
170         if(NS_FAILED(nsres))
171             ERR("GetRangeAt failed: %08x\n", nsres);
172     }
173 
174     hres = HTMLTxtRange_Create(This->doc, nsrange, &range_obj);
175 
176     if (nsrange) nsIDOMRange_Release(nsrange);
177     *range = (IDispatch*)range_obj;
178     return hres;
179 }
180 
181 static HRESULT WINAPI HTMLSelectionObject_empty(IHTMLSelectionObject *iface)
182 {
183     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
184     FIXME("(%p)\n", This);
185     return E_NOTIMPL;
186 }
187 
188 static HRESULT WINAPI HTMLSelectionObject_clear(IHTMLSelectionObject *iface)
189 {
190     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
191     FIXME("(%p)\n", This);
192     return E_NOTIMPL;
193 }
194 
195 static HRESULT WINAPI HTMLSelectionObject_get_type(IHTMLSelectionObject *iface, BSTR *p)
196 {
197     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
198     cpp_bool collapsed = TRUE;
199 
200     static const WCHAR wszNone[] = {'N','o','n','e',0};
201     static const WCHAR wszText[] = {'T','e','x','t',0};
202 
203     TRACE("(%p)->(%p)\n", This, p);
204 
205     if(This->nsselection)
206         nsISelection_GetIsCollapsed(This->nsselection, &collapsed);
207 
208     *p = SysAllocString(collapsed ? wszNone : wszText); /* FIXME: control */
209     TRACE("ret %s\n", debugstr_w(*p));
210     return S_OK;
211 }
212 
213 static const IHTMLSelectionObjectVtbl HTMLSelectionObjectVtbl = {
214     HTMLSelectionObject_QueryInterface,
215     HTMLSelectionObject_AddRef,
216     HTMLSelectionObject_Release,
217     HTMLSelectionObject_GetTypeInfoCount,
218     HTMLSelectionObject_GetTypeInfo,
219     HTMLSelectionObject_GetIDsOfNames,
220     HTMLSelectionObject_Invoke,
221     HTMLSelectionObject_createRange,
222     HTMLSelectionObject_empty,
223     HTMLSelectionObject_clear,
224     HTMLSelectionObject_get_type
225 };
226 
227 static inline HTMLSelectionObject *impl_from_IHTMLSelectionObject2(IHTMLSelectionObject2 *iface)
228 {
229     return CONTAINING_RECORD(iface, HTMLSelectionObject, IHTMLSelectionObject2_iface);
230 }
231 
232 static HRESULT WINAPI HTMLSelectionObject2_QueryInterface(IHTMLSelectionObject2 *iface, REFIID riid, void **ppv)
233 {
234     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
235 
236     return IHTMLSelectionObject_QueryInterface(&This->IHTMLSelectionObject_iface, riid, ppv);
237 }
238 
239 static ULONG WINAPI HTMLSelectionObject2_AddRef(IHTMLSelectionObject2 *iface)
240 {
241     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
242 
243     return IHTMLSelectionObject_AddRef(&This->IHTMLSelectionObject_iface);
244 }
245 
246 static ULONG WINAPI HTMLSelectionObject2_Release(IHTMLSelectionObject2 *iface)
247 {
248     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
249 
250     return IHTMLSelectionObject_Release(&This->IHTMLSelectionObject_iface);
251 }
252 
253 static HRESULT WINAPI HTMLSelectionObject2_GetTypeInfoCount(IHTMLSelectionObject2 *iface, UINT *pctinfo)
254 {
255     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
256 
257     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
258 }
259 
260 static HRESULT WINAPI HTMLSelectionObject2_GetTypeInfo(IHTMLSelectionObject2 *iface, UINT iTInfo,
261         LCID lcid, ITypeInfo **ppTInfo)
262 {
263     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
264 
265     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
266 }
267 
268 static HRESULT WINAPI HTMLSelectionObject2_GetIDsOfNames(IHTMLSelectionObject2 *iface, REFIID riid,
269         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
270 {
271     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
272 
273     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames,
274             cNames, lcid, rgDispId);
275 }
276 
277 static HRESULT WINAPI HTMLSelectionObject2_Invoke(IHTMLSelectionObject2 *iface, DISPID dispIdMember,
278         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
279         EXCEPINFO *pExcepInfo, UINT *puArgErr)
280 {
281     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
282 
283     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid,
284             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
285 }
286 
287 static HRESULT WINAPI HTMLSelectionObject2_createRangeCollection(IHTMLSelectionObject2 *iface, IDispatch **rangeCollection)
288 {
289     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
290     FIXME("(%p)->(%p)\n", This, rangeCollection);
291     return E_NOTIMPL;
292 }
293 
294 static HRESULT WINAPI HTMLSelectionObject2_get_typeDetail(IHTMLSelectionObject2 *iface, BSTR *p)
295 {
296     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
297     FIXME("(%p)->(%p)\n", This, p);
298     return E_NOTIMPL;
299 }
300 
301 static const IHTMLSelectionObject2Vtbl HTMLSelectionObject2Vtbl = {
302     HTMLSelectionObject2_QueryInterface,
303     HTMLSelectionObject2_AddRef,
304     HTMLSelectionObject2_Release,
305     HTMLSelectionObject2_GetTypeInfoCount,
306     HTMLSelectionObject2_GetTypeInfo,
307     HTMLSelectionObject2_GetIDsOfNames,
308     HTMLSelectionObject2_Invoke,
309     HTMLSelectionObject2_createRangeCollection,
310     HTMLSelectionObject2_get_typeDetail
311 };
312 
313 static const tid_t HTMLSelectionObject_iface_tids[] = {
314     IHTMLSelectionObject_tid,
315     IHTMLSelectionObject2_tid,
316     0
317 };
318 static dispex_static_data_t HTMLSelectionObject_dispex = {
319     NULL,
320     IHTMLSelectionObject_tid, /* FIXME: We have a test for that, but it doesn't expose IHTMLSelectionObject2 iface. */
321     NULL,
322     HTMLSelectionObject_iface_tids
323 };
324 
325 HRESULT HTMLSelectionObject_Create(HTMLDocumentNode *doc, nsISelection *nsselection, IHTMLSelectionObject **ret)
326 {
327     HTMLSelectionObject *selection;
328 
329     selection = heap_alloc(sizeof(HTMLSelectionObject));
330     if(!selection)
331         return E_OUTOFMEMORY;
332 
333     init_dispex(&selection->dispex, (IUnknown*)&selection->IHTMLSelectionObject_iface, &HTMLSelectionObject_dispex);
334 
335     selection->IHTMLSelectionObject_iface.lpVtbl = &HTMLSelectionObjectVtbl;
336     selection->IHTMLSelectionObject2_iface.lpVtbl = &HTMLSelectionObject2Vtbl;
337     selection->ref = 1;
338     selection->nsselection = nsselection; /* We shouldn't call AddRef here */
339 
340     selection->doc = doc;
341     list_add_head(&doc->selection_list, &selection->entry);
342 
343     *ret = &selection->IHTMLSelectionObject_iface;
344     return S_OK;
345 }
346 
347 void detach_selection(HTMLDocumentNode *This)
348 {
349     HTMLSelectionObject *iter;
350 
351     LIST_FOR_EACH_ENTRY(iter, &This->selection_list, HTMLSelectionObject, entry) {
352         iter->doc = NULL;
353     }
354 }
355