gdiplus: Add test for GdipSetTextRenderingHint and make it pass.
[wine] / dlls / mshtml / htmllocation.c
1 /*
2  * Copyright 2008 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 <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "ole2.h"
28 #include "wininet.h"
29 #include "shlwapi.h"
30
31 #include "wine/debug.h"
32
33 #include "mshtml_private.h"
34 #include "resource.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret)
39 {
40     if(!This->window || !This->window->url) {
41         FIXME("No current URL\n");
42         return E_NOTIMPL;
43     }
44
45     *ret = This->window->url;
46     return S_OK;
47 }
48
49 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url)
50 {
51     const WCHAR *doc_url;
52     HRESULT hres;
53
54     hres = get_url(This, &doc_url);
55     if(FAILED(hres))
56         return hres;
57
58     if(!InternetCrackUrlW(doc_url, 0, 0, url)) {
59         FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError());
60         SetLastError(0);
61         return E_FAIL;
62     }
63
64     return S_OK;
65 }
66
67 static inline HTMLLocation *impl_from_IHTMLLocation(IHTMLLocation *iface)
68 {
69     return CONTAINING_RECORD(iface, HTMLLocation, IHTMLLocation_iface);
70 }
71
72 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv)
73 {
74     HTMLLocation *This = impl_from_IHTMLLocation(iface);
75
76     *ppv = NULL;
77
78     if(IsEqualGUID(&IID_IUnknown, riid)) {
79         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
80         *ppv = &This->IHTMLLocation_iface;
81     }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) {
82         TRACE("(%p)->(IID_IHTMLLocation %p)\n", This, ppv);
83         *ppv = &This->IHTMLLocation_iface;
84     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
85         return *ppv ? S_OK : E_NOINTERFACE;
86     }
87
88     if(*ppv) {
89         IUnknown_AddRef((IUnknown*)*ppv);
90         return S_OK;
91     }
92
93     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
94     return E_NOINTERFACE;
95 }
96
97 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface)
98 {
99     HTMLLocation *This = impl_from_IHTMLLocation(iface);
100     LONG ref = InterlockedIncrement(&This->ref);
101
102     TRACE("(%p) ref=%d\n", This, ref);
103
104     return ref;
105 }
106
107 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
108 {
109     HTMLLocation *This = impl_from_IHTMLLocation(iface);
110     LONG ref = InterlockedDecrement(&This->ref);
111
112     TRACE("(%p) ref=%d\n", This, ref);
113
114     if(!ref) {
115         if(This->window)
116             This->window->location = NULL;
117         release_dispex(&This->dispex);
118         heap_free(This);
119     }
120
121     return ref;
122 }
123
124 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo)
125 {
126     HTMLLocation *This = impl_from_IHTMLLocation(iface);
127     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
128 }
129
130 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo,
131                                               LCID lcid, ITypeInfo **ppTInfo)
132 {
133     HTMLLocation *This = impl_from_IHTMLLocation(iface);
134     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
135 }
136
137 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid,
138                                                 LPOLESTR *rgszNames, UINT cNames,
139                                                 LCID lcid, DISPID *rgDispId)
140 {
141     HTMLLocation *This = impl_from_IHTMLLocation(iface);
142     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
143             lcid, rgDispId);
144 }
145
146 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember,
147                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
148                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
149 {
150     HTMLLocation *This = impl_from_IHTMLLocation(iface);
151     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
152             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
153 }
154
155 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
156 {
157     HTMLLocation *This = impl_from_IHTMLLocation(iface);
158
159     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
160
161     if(!This->window) {
162         FIXME("No window available\n");
163         return E_FAIL;
164     }
165
166     return navigate_url(This->window, v, This->window->url);
167 }
168
169 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
170 {
171     HTMLLocation *This = impl_from_IHTMLLocation(iface);
172     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
173     WCHAR *buf = NULL, *url_path = NULL;
174     HRESULT hres, ret;
175     DWORD len = 0;
176     int i;
177
178     TRACE("(%p)->(%p)\n", This, p);
179
180     if(!p)
181         return E_POINTER;
182
183     url.dwSchemeLength = 1;
184     url.dwHostNameLength = 1;
185     url.dwUrlPathLength = 1;
186     url.dwExtraInfoLength = 1;
187     hres = get_url_components(This, &url);
188     if(FAILED(hres))
189         return hres;
190
191     switch(url.nScheme) {
192     case INTERNET_SCHEME_FILE:
193         {
194             /* prepend a slash */
195             url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
196             if(!url_path)
197                 return E_OUTOFMEMORY;
198             url_path[0] = '/';
199             memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
200             url.lpszUrlPath = url_path;
201             url.dwUrlPathLength = url.dwUrlPathLength + 1;
202         }
203         break;
204
205     case INTERNET_SCHEME_HTTP:
206     case INTERNET_SCHEME_HTTPS:
207     case INTERNET_SCHEME_FTP:
208         if(!url.dwUrlPathLength) {
209             /* add a slash if it's blank */
210             url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR));
211             if(!url.lpszUrlPath)
212                 return E_OUTOFMEMORY;
213             url.lpszUrlPath[0] = '/';
214             url.dwUrlPathLength = 1;
215         }
216         break;
217
218     default:
219         break;
220     }
221
222     /* replace \ with / */
223     for(i = 0; i < url.dwUrlPathLength; ++i)
224         if(url.lpszUrlPath[i] == '\\')
225             url.lpszUrlPath[i] = '/';
226
227     if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) {
228         FIXME("InternetCreateUrl succeeded with NULL buffer?\n");
229         ret = E_FAIL;
230         goto cleanup;
231     }
232
233     if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
234         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
235         SetLastError(0);
236         ret = E_FAIL;
237         goto cleanup;
238     }
239     SetLastError(0);
240
241     buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
242     if(!buf) {
243         ret = E_OUTOFMEMORY;
244         goto cleanup;
245     }
246
247     if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) {
248         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
249         SetLastError(0);
250         ret = E_FAIL;
251         goto cleanup;
252     }
253
254     *p = SysAllocStringLen(buf, len);
255     if(!*p) {
256         ret = E_OUTOFMEMORY;
257         goto cleanup;
258     }
259
260     ret = S_OK;
261
262 cleanup:
263     HeapFree(GetProcessHeap(), 0, buf);
264     HeapFree(GetProcessHeap(), 0, url_path);
265
266     return ret;
267 }
268
269 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
270 {
271     HTMLLocation *This = impl_from_IHTMLLocation(iface);
272     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
273     return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p)
277 {
278     HTMLLocation *This = impl_from_IHTMLLocation(iface);
279     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
280     HRESULT hres;
281
282     TRACE("(%p)->(%p)\n", This, p);
283
284     if(!p)
285         return E_POINTER;
286
287     url.dwSchemeLength = 1;
288     hres = get_url_components(This, &url);
289     if(FAILED(hres))
290         return hres;
291
292     if(!url.dwSchemeLength) {
293         FIXME("Unexpected blank protocol\n");
294         return E_NOTIMPL;
295     }else {
296         WCHAR buf[url.dwSchemeLength + 1];
297         memcpy(buf, url.lpszScheme, url.dwSchemeLength * sizeof(WCHAR));
298         buf[url.dwSchemeLength] = ':';
299         *p = SysAllocStringLen(buf, url.dwSchemeLength + 1);
300     }
301     if(!*p)
302         return E_OUTOFMEMORY;
303     return S_OK;
304 }
305
306 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v)
307 {
308     HTMLLocation *This = impl_from_IHTMLLocation(iface);
309     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
310     return E_NOTIMPL;
311 }
312
313 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p)
314 {
315     HTMLLocation *This = impl_from_IHTMLLocation(iface);
316     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
317     HRESULT hres;
318
319     TRACE("(%p)->(%p)\n", This, p);
320
321     if(!p)
322         return E_POINTER;
323
324     url.dwHostNameLength = 1;
325     hres = get_url_components(This, &url);
326     if(FAILED(hres))
327         return hres;
328
329     if(!url.dwHostNameLength){
330         *p = NULL;
331         return S_OK;
332     }
333
334     if(url.nPort) {
335         /* <hostname>:<port> */
336         const WCHAR format[] = {'%','u',0};
337         DWORD len = url.dwHostNameLength + 1 + 5 + 1;
338         WCHAR buf[len];
339
340         memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
341         buf[url.dwHostNameLength] = ':';
342         snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort);
343         *p = SysAllocString(buf);
344     }else
345         *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
346
347     if(!*p)
348         return E_OUTOFMEMORY;
349     return S_OK;
350 }
351
352 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v)
353 {
354     HTMLLocation *This = impl_from_IHTMLLocation(iface);
355     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
356     return E_NOTIMPL;
357 }
358
359 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p)
360 {
361     HTMLLocation *This = impl_from_IHTMLLocation(iface);
362     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
363     HRESULT hres;
364
365     TRACE("(%p)->(%p)\n", This, p);
366
367     if(!p)
368         return E_POINTER;
369
370     url.dwHostNameLength = 1;
371     hres = get_url_components(This, &url);
372     if(FAILED(hres))
373         return hres;
374
375     if(!url.dwHostNameLength){
376         *p = NULL;
377         return S_OK;
378     }
379
380     *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
381     if(!*p)
382         return E_OUTOFMEMORY;
383     return S_OK;
384 }
385
386 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v)
387 {
388     HTMLLocation *This = impl_from_IHTMLLocation(iface);
389     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
390     return E_NOTIMPL;
391 }
392
393 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p)
394 {
395     HTMLLocation *This = impl_from_IHTMLLocation(iface);
396     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
397     HRESULT hres;
398
399     TRACE("(%p)->(%p)\n", This, p);
400
401     if(!p)
402         return E_POINTER;
403
404     hres = get_url_components(This, &url);
405     if(FAILED(hres))
406         return hres;
407
408     if(url.nPort) {
409         const WCHAR format[] = {'%','u',0};
410         WCHAR buf[6];
411         snprintfW(buf, 6, format, url.nPort);
412         *p = SysAllocString(buf);
413     }else {
414         const WCHAR empty[] = {0};
415         *p = SysAllocString(empty);
416     }
417
418     if(!*p)
419         return E_OUTOFMEMORY;
420     return S_OK;
421 }
422
423 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
424 {
425     HTMLLocation *This = impl_from_IHTMLLocation(iface);
426     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
427     return E_NOTIMPL;
428 }
429
430 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
431 {
432     HTMLLocation *This = impl_from_IHTMLLocation(iface);
433     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
434     HRESULT hres;
435
436     TRACE("(%p)->(%p)\n", This, p);
437
438     if(!p)
439         return E_POINTER;
440
441     url.dwUrlPathLength = 1;
442     url.dwExtraInfoLength = 1;
443     hres = get_url_components(This, &url);
444     if(FAILED(hres))
445         return hres;
446
447     if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/')
448         *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1);
449     else
450         *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
451
452     if(!*p)
453         return E_OUTOFMEMORY;
454     return S_OK;
455 }
456
457 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
458 {
459     HTMLLocation *This = impl_from_IHTMLLocation(iface);
460     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
461     return E_NOTIMPL;
462 }
463
464 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p)
465 {
466     HTMLLocation *This = impl_from_IHTMLLocation(iface);
467     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
468     HRESULT hres;
469     const WCHAR hash[] = {'#',0};
470
471     TRACE("(%p)->(%p)\n", This, p);
472
473     if(!p)
474         return E_POINTER;
475
476     url.dwExtraInfoLength = 1;
477     hres = get_url_components(This, &url);
478     if(FAILED(hres))
479         return hres;
480
481     if(!url.dwExtraInfoLength){
482         *p = NULL;
483         return S_OK;
484     }
485
486     url.dwExtraInfoLength = strcspnW(url.lpszExtraInfo, hash);
487
488     *p = SysAllocStringLen(url.lpszExtraInfo, url.dwExtraInfoLength);
489
490     if(!*p)
491         return E_OUTOFMEMORY;
492     return S_OK;
493 }
494
495 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v)
496 {
497     HTMLLocation *This = impl_from_IHTMLLocation(iface);
498     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
499     return E_NOTIMPL;
500 }
501
502 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
503 {
504     HTMLLocation *This = impl_from_IHTMLLocation(iface);
505     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
506     const WCHAR hash[] = {'#',0};
507     DWORD hash_pos = 0;
508     HRESULT hres;
509
510     TRACE("(%p)->(%p)\n", This, p);
511
512     if(!p)
513         return E_POINTER;
514
515     url.dwExtraInfoLength = 1;
516     hres = get_url_components(This, &url);
517     if(FAILED(hres))
518         return hres;
519
520     if(!url.dwExtraInfoLength){
521         *p = NULL;
522         return S_OK;
523     }
524
525     hash_pos = strcspnW(url.lpszExtraInfo, hash);
526     url.dwExtraInfoLength -= hash_pos;
527
528     *p = SysAllocStringLen(url.lpszExtraInfo + hash_pos, url.dwExtraInfoLength);
529
530     if(!*p)
531         return E_OUTOFMEMORY;
532     return S_OK;
533 }
534
535 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
536 {
537     HTMLLocation *This = impl_from_IHTMLLocation(iface);
538     FIXME("(%p)->(%x)\n", This, flag);
539     return E_NOTIMPL;
540 }
541
542 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
543 {
544     HTMLLocation *This = impl_from_IHTMLLocation(iface);
545
546     TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
547
548     if(!This->window) {
549         FIXME("No window available\n");
550         return E_FAIL;
551     }
552
553     return navigate_url(This->window, bstr, This->window->url);
554 }
555
556 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
557 {
558     HTMLLocation *This = impl_from_IHTMLLocation(iface);
559     FIXME("(%p)->(%s)\n", This, debugstr_w(bstr));
560     return E_NOTIMPL;
561 }
562
563 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
564 {
565     HTMLLocation *This = impl_from_IHTMLLocation(iface);
566     FIXME("(%p)->(%p)\n", This, String);
567     return E_NOTIMPL;
568 }
569
570 static const IHTMLLocationVtbl HTMLLocationVtbl = {
571     HTMLLocation_QueryInterface,
572     HTMLLocation_AddRef,
573     HTMLLocation_Release,
574     HTMLLocation_GetTypeInfoCount,
575     HTMLLocation_GetTypeInfo,
576     HTMLLocation_GetIDsOfNames,
577     HTMLLocation_Invoke,
578     HTMLLocation_put_href,
579     HTMLLocation_get_href,
580     HTMLLocation_put_protocol,
581     HTMLLocation_get_protocol,
582     HTMLLocation_put_host,
583     HTMLLocation_get_host,
584     HTMLLocation_put_hostname,
585     HTMLLocation_get_hostname,
586     HTMLLocation_put_port,
587     HTMLLocation_get_port,
588     HTMLLocation_put_pathname,
589     HTMLLocation_get_pathname,
590     HTMLLocation_put_search,
591     HTMLLocation_get_search,
592     HTMLLocation_put_hash,
593     HTMLLocation_get_hash,
594     HTMLLocation_reload,
595     HTMLLocation_replace,
596     HTMLLocation_assign,
597     HTMLLocation_toString
598 };
599
600 static const tid_t HTMLLocation_iface_tids[] = {
601     IHTMLLocation_tid,
602     0
603 };
604 static dispex_static_data_t HTMLLocation_dispex = {
605     NULL,
606     DispHTMLLocation_tid,
607     NULL,
608     HTMLLocation_iface_tids
609 };
610
611
612 HRESULT HTMLLocation_Create(HTMLWindow *window, HTMLLocation **ret)
613 {
614     HTMLLocation *location;
615
616     location = heap_alloc(sizeof(*location));
617     if(!location)
618         return E_OUTOFMEMORY;
619
620     location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl;
621     location->ref = 1;
622     location->window = window;
623
624     init_dispex(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex);
625
626     *ret = location;
627     return S_OK;
628 }