xref: /reactos/dll/win32/mshtml/htmlanchor.c (revision 5e2fe089)
1 /*
2  * Copyright 2007 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     HTMLElement element;
23 
24     IHTMLAnchorElement IHTMLAnchorElement_iface;
25 
26     nsIDOMHTMLAnchorElement *nsanchor;
27 } HTMLAnchorElement;
28 
29 static HRESULT navigate_href_new_window(HTMLElement *element, nsAString *href_str, const WCHAR *target)
30 {
31     const PRUnichar *href;
32     IUri *uri;
33     HRESULT hres;
34 
35     nsAString_GetData(href_str, &href);
36     hres = create_relative_uri(element->node.doc->basedoc.window, href, &uri);
37     if(FAILED(hres))
38         return hres;
39 
40     hres = navigate_new_window(element->node.doc->basedoc.window, uri, target, NULL, NULL);
41     IUri_Release(uri);
42     return hres;
43 }
44 
45 HTMLOuterWindow *get_target_window(HTMLOuterWindow *window, nsAString *target_str, BOOL *use_new_window)
46 {
47     HTMLOuterWindow *top_window, *ret_window;
48     const PRUnichar *target;
49     HRESULT hres;
50 
51     static const WCHAR _parentW[] = {'_','p','a','r','e','n','t',0};
52     static const WCHAR _selfW[] = {'_','s','e','l','f',0};
53     static const WCHAR _topW[] = {'_','t','o','p',0};
54 
55     *use_new_window = FALSE;
56 
57     nsAString_GetData(target_str, &target);
58     TRACE("%s\n", debugstr_w(target));
59 
60     if(!*target || !strcmpiW(target, _selfW)) {
61         IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
62         return window;
63     }
64 
65     if(!strcmpiW(target, _topW)) {
66         get_top_window(window, &top_window);
67         IHTMLWindow2_AddRef(&top_window->base.IHTMLWindow2_iface);
68         return top_window;
69     }
70 
71     if(!strcmpiW(target, _parentW)) {
72         if(!window->parent) {
73             WARN("Window has no parent, treat as self\n");
74             IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
75             return window;
76         }
77 
78         IHTMLWindow2_AddRef(&window->parent->base.IHTMLWindow2_iface);
79         return window->parent;
80     }
81 
82     get_top_window(window, &top_window);
83 
84     hres = get_frame_by_name(top_window, target, TRUE, &ret_window);
85     if(FAILED(hres) || !ret_window) {
86         *use_new_window = TRUE;
87         return NULL;
88     }
89 
90     IHTMLWindow2_AddRef(&ret_window->base.IHTMLWindow2_iface);
91     return ret_window;
92 }
93 
94 static HRESULT navigate_href(HTMLElement *element, nsAString *href_str, nsAString *target_str)
95 {
96     HTMLOuterWindow *window;
97     BOOL use_new_window;
98     const PRUnichar *href;
99     HRESULT hres;
100 
101     window = get_target_window(element->node.doc->basedoc.window, target_str, &use_new_window);
102     if(!window) {
103         if(use_new_window) {
104             const PRUnichar *target;
105             nsAString_GetData(target_str, &target);
106             return navigate_href_new_window(element, href_str, target);
107         }else {
108             return S_OK;
109         }
110     }
111 
112     nsAString_GetData(href_str, &href);
113     if(*href) {
114         hres = navigate_url(window, href, window->uri_nofrag, BINDING_NAVIGATED);
115     }else {
116         TRACE("empty href\n");
117         hres = S_OK;
118     }
119     IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
120     return hres;
121 }
122 
123 HRESULT handle_link_click_event(HTMLElement *element, nsAString *href_str, nsAString *target_str,
124                                 nsIDOMEvent *event, BOOL *prevent_default)
125 {
126     nsIDOMMouseEvent *mouse_event;
127     INT16 button;
128     nsresult nsres;
129     HRESULT hres;
130 
131     TRACE("CLICK\n");
132 
133     nsres = nsIDOMEvent_QueryInterface(event, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
134     assert(nsres == NS_OK);
135 
136     nsres = nsIDOMMouseEvent_GetButton(mouse_event, &button);
137     assert(nsres == NS_OK);
138 
139     nsIDOMMouseEvent_Release(mouse_event);
140 
141     switch(button) {
142     case 0:
143         *prevent_default = TRUE;
144         hres = navigate_href(element, href_str, target_str);
145         break;
146     case 1:
147         *prevent_default = TRUE;
148         hres = navigate_href_new_window(element, href_str, NULL);
149         break;
150     default:
151         *prevent_default = FALSE;
152         hres = S_OK;
153     }
154 
155     nsAString_Finish(href_str);
156     nsAString_Finish(target_str);
157     return hres;
158 }
159 
160 static inline HTMLAnchorElement *impl_from_IHTMLAnchorElement(IHTMLAnchorElement *iface)
161 {
162     return CONTAINING_RECORD(iface, HTMLAnchorElement, IHTMLAnchorElement_iface);
163 }
164 
165 static HRESULT WINAPI HTMLAnchorElement_QueryInterface(IHTMLAnchorElement *iface,
166         REFIID riid, void **ppv)
167 {
168     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
169 
170     return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv);
171 }
172 
173 static ULONG WINAPI HTMLAnchorElement_AddRef(IHTMLAnchorElement *iface)
174 {
175     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
176 
177     return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface);
178 }
179 
180 static ULONG WINAPI HTMLAnchorElement_Release(IHTMLAnchorElement *iface)
181 {
182     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
183 
184     return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface);
185 }
186 
187 static HRESULT WINAPI HTMLAnchorElement_GetTypeInfoCount(IHTMLAnchorElement *iface, UINT *pctinfo)
188 {
189     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
190     return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo);
191 }
192 
193 static HRESULT WINAPI HTMLAnchorElement_GetTypeInfo(IHTMLAnchorElement *iface, UINT iTInfo,
194                                               LCID lcid, ITypeInfo **ppTInfo)
195 {
196     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
197     return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid,
198             ppTInfo);
199 }
200 
201 static HRESULT WINAPI HTMLAnchorElement_GetIDsOfNames(IHTMLAnchorElement *iface, REFIID riid,
202                                                 LPOLESTR *rgszNames, UINT cNames,
203                                                 LCID lcid, DISPID *rgDispId)
204 {
205     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
206     return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames,
207             cNames, lcid, rgDispId);
208 }
209 
210 static HRESULT WINAPI HTMLAnchorElement_Invoke(IHTMLAnchorElement *iface, DISPID dispIdMember,
211                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
212                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
213 {
214     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
215     return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid,
216             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
217 }
218 
219 static HRESULT WINAPI HTMLAnchorElement_put_href(IHTMLAnchorElement *iface, BSTR v)
220 {
221     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
222     nsAString nsstr;
223     nsresult nsres;
224 
225     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
226 
227     nsAString_InitDepend(&nsstr, v);
228     nsres = nsIDOMHTMLAnchorElement_SetHref(This->nsanchor, &nsstr);
229     nsAString_Finish(&nsstr);
230     if(NS_FAILED(nsres))
231         return E_FAIL;
232 
233     return S_OK;
234 }
235 
236 static HRESULT WINAPI HTMLAnchorElement_get_href(IHTMLAnchorElement *iface, BSTR *p)
237 {
238     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
239     nsAString href_str;
240     nsresult nsres;
241     HRESULT hres;
242 
243     TRACE("(%p)->(%p)\n", This, p);
244 
245     nsAString_Init(&href_str, NULL);
246     nsres = nsIDOMHTMLAnchorElement_GetHref(This->nsanchor, &href_str);
247     if(NS_SUCCEEDED(nsres)) {
248         const PRUnichar *href;
249 
250         nsAString_GetData(&href_str, &href);
251         hres = nsuri_to_url(href, TRUE, p);
252     }else {
253         ERR("GetHref failed: %08x\n", nsres);
254         hres = E_FAIL;
255     }
256 
257     nsAString_Finish(&href_str);
258     return hres;
259 }
260 
261 static HRESULT WINAPI HTMLAnchorElement_put_target(IHTMLAnchorElement *iface, BSTR v)
262 {
263     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
264     nsAString nsstr;
265     nsresult nsres;
266 
267     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
268 
269     nsAString_InitDepend(&nsstr, v);
270     nsres = nsIDOMHTMLAnchorElement_SetTarget(This->nsanchor, &nsstr);
271     nsAString_Finish(&nsstr);
272     if(NS_FAILED(nsres))
273         return E_FAIL;
274 
275     return S_OK;
276 }
277 
278 static HRESULT WINAPI HTMLAnchorElement_get_target(IHTMLAnchorElement *iface, BSTR *p)
279 {
280     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
281     nsAString target_str;
282     nsresult nsres;
283 
284     TRACE("(%p)->(%p)\n", This, p);
285 
286     nsAString_Init(&target_str, NULL);
287     nsres = nsIDOMHTMLAnchorElement_GetTarget(This->nsanchor, &target_str);
288 
289     return return_nsstr(nsres, &target_str, p);
290 }
291 
292 static HRESULT WINAPI HTMLAnchorElement_put_rel(IHTMLAnchorElement *iface, BSTR v)
293 {
294     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
295     nsAString nsstr;
296     nsresult nsres;
297 
298     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
299 
300     nsAString_InitDepend(&nsstr, v);
301     nsres = nsIDOMHTMLAnchorElement_SetRel(This->nsanchor, &nsstr);
302     nsAString_Finish(&nsstr);
303     if(NS_FAILED(nsres))
304         return E_FAIL;
305 
306     return S_OK;
307 }
308 
309 static HRESULT WINAPI HTMLAnchorElement_get_rel(IHTMLAnchorElement *iface, BSTR *p)
310 {
311     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
312     nsAString nsstr;
313     nsresult nsres;
314 
315     TRACE("(%p)->(%p)\n", This, p);
316 
317     nsAString_Init(&nsstr, NULL);
318     nsres = nsIDOMHTMLAnchorElement_GetRel(This->nsanchor, &nsstr);
319     return return_nsstr(nsres, &nsstr, p);
320 }
321 
322 static HRESULT WINAPI HTMLAnchorElement_put_rev(IHTMLAnchorElement *iface, BSTR v)
323 {
324     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
325     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
326     return E_NOTIMPL;
327 }
328 
329 static HRESULT WINAPI HTMLAnchorElement_get_rev(IHTMLAnchorElement *iface, BSTR *p)
330 {
331     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
332     FIXME("(%p)->(%p)\n", This, p);
333     return E_NOTIMPL;
334 }
335 
336 static HRESULT WINAPI HTMLAnchorElement_put_urn(IHTMLAnchorElement *iface, BSTR v)
337 {
338     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
339     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
340     return E_NOTIMPL;
341 }
342 
343 static HRESULT WINAPI HTMLAnchorElement_get_urn(IHTMLAnchorElement *iface, BSTR *p)
344 {
345     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
346     FIXME("(%p)->(%p)\n", This, p);
347     return E_NOTIMPL;
348 }
349 
350 static HRESULT WINAPI HTMLAnchorElement_put_Methods(IHTMLAnchorElement *iface, BSTR v)
351 {
352     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
353     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
354     return E_NOTIMPL;
355 }
356 
357 static HRESULT WINAPI HTMLAnchorElement_get_Methods(IHTMLAnchorElement *iface, BSTR *p)
358 {
359     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
360     FIXME("(%p)->(%p)\n", This, p);
361     return E_NOTIMPL;
362 }
363 
364 static HRESULT WINAPI HTMLAnchorElement_put_name(IHTMLAnchorElement *iface, BSTR v)
365 {
366     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
367     nsAString nsstr;
368     nsresult nsres;
369 
370     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
371 
372     nsAString_InitDepend(&nsstr, v);
373     nsres = nsIDOMHTMLAnchorElement_SetName(This->nsanchor, &nsstr);
374     nsAString_Finish(&nsstr);
375     if(NS_FAILED(nsres))
376         return E_FAIL;
377 
378     return S_OK;
379 }
380 
381 static HRESULT WINAPI HTMLAnchorElement_get_name(IHTMLAnchorElement *iface, BSTR *p)
382 {
383     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
384     nsAString name_str;
385     nsresult nsres;
386 
387     TRACE("(%p)->(%p)\n", This, p);
388 
389     nsAString_Init(&name_str, NULL);
390     nsres = nsIDOMHTMLAnchorElement_GetName(This->nsanchor, &name_str);
391 
392     return return_nsstr(nsres, &name_str, p);
393 }
394 
395 static HRESULT WINAPI HTMLAnchorElement_put_host(IHTMLAnchorElement *iface, BSTR v)
396 {
397     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
398     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
399     return E_NOTIMPL;
400 }
401 
402 static HRESULT WINAPI HTMLAnchorElement_get_host(IHTMLAnchorElement *iface, BSTR *p)
403 {
404     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
405     FIXME("(%p)->(%p)\n", This, p);
406     return E_NOTIMPL;
407 }
408 
409 static HRESULT WINAPI HTMLAnchorElement_put_hostname(IHTMLAnchorElement *iface, BSTR v)
410 {
411     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
412     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
413     return E_NOTIMPL;
414 }
415 
416 static HRESULT WINAPI HTMLAnchorElement_get_hostname(IHTMLAnchorElement *iface, BSTR *p)
417 {
418     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
419     nsAString hostname_str;
420     nsresult nsres;
421 
422     TRACE("(%p)->(%p)\n", This, p);
423 
424     nsAString_Init(&hostname_str, NULL);
425     nsres = nsIDOMHTMLAnchorElement_GetHostname(This->nsanchor, &hostname_str);
426     return return_nsstr(nsres, &hostname_str, p);
427 }
428 
429 static HRESULT WINAPI HTMLAnchorElement_put_pathname(IHTMLAnchorElement *iface, BSTR v)
430 {
431     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
432     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
433     return E_NOTIMPL;
434 }
435 
436 static HRESULT WINAPI HTMLAnchorElement_get_pathname(IHTMLAnchorElement *iface, BSTR *p)
437 {
438     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
439     FIXME("(%p)->(%p)\n", This, p);
440     return E_NOTIMPL;
441 }
442 
443 static HRESULT WINAPI HTMLAnchorElement_put_port(IHTMLAnchorElement *iface, BSTR v)
444 {
445     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
446     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
447     return E_NOTIMPL;
448 }
449 
450 static HRESULT WINAPI HTMLAnchorElement_get_port(IHTMLAnchorElement *iface, BSTR *p)
451 {
452     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
453     FIXME("(%p)->(%p)\n", This, p);
454     return E_NOTIMPL;
455 }
456 
457 static HRESULT WINAPI HTMLAnchorElement_put_protocol(IHTMLAnchorElement *iface, BSTR v)
458 {
459     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
460     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
461     return E_NOTIMPL;
462 }
463 
464 static HRESULT WINAPI HTMLAnchorElement_get_protocol(IHTMLAnchorElement *iface, BSTR *p)
465 {
466     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
467     FIXME("(%p)->(%p)\n", This, p);
468     return E_NOTIMPL;
469 }
470 
471 static HRESULT WINAPI HTMLAnchorElement_put_search(IHTMLAnchorElement *iface, BSTR v)
472 {
473     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
474     nsAString nsstr;
475     nsresult nsres;
476 
477     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
478 
479     nsAString_InitDepend(&nsstr, v);
480     nsres = nsIDOMHTMLAnchorElement_SetSearch(This->nsanchor, &nsstr);
481     nsAString_Finish(&nsstr);
482     if(NS_FAILED(nsres))
483         return E_FAIL;
484 
485     return S_OK;
486 }
487 
488 static HRESULT WINAPI HTMLAnchorElement_get_search(IHTMLAnchorElement *iface, BSTR *p)
489 {
490     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
491     nsAString search_str;
492     nsresult nsres;
493 
494     TRACE("(%p)->(%p)\n", This, p);
495 
496     nsAString_Init(&search_str, NULL);
497     nsres = nsIDOMHTMLAnchorElement_GetSearch(This->nsanchor, &search_str);
498     return return_nsstr(nsres, &search_str, p);
499 }
500 
501 static HRESULT WINAPI HTMLAnchorElement_put_hash(IHTMLAnchorElement *iface, BSTR v)
502 {
503     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
504     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
505     return E_NOTIMPL;
506 }
507 
508 static HRESULT WINAPI HTMLAnchorElement_get_hash(IHTMLAnchorElement *iface, BSTR *p)
509 {
510     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
511     nsAString hash_str;
512     nsresult nsres;
513 
514     TRACE("(%p)->(%p)\n", This, p);
515 
516     nsAString_Init(&hash_str, NULL);
517     nsres = nsIDOMHTMLAnchorElement_GetHash(This->nsanchor, &hash_str);
518     return return_nsstr(nsres, &hash_str, p);
519 }
520 
521 static HRESULT WINAPI HTMLAnchorElement_put_onblur(IHTMLAnchorElement *iface, VARIANT v)
522 {
523     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
524 
525     TRACE("(%p)->()\n", This);
526 
527     return IHTMLElement2_put_onblur(&This->element.IHTMLElement2_iface, v);
528 }
529 
530 static HRESULT WINAPI HTMLAnchorElement_get_onblur(IHTMLAnchorElement *iface, VARIANT *p)
531 {
532     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
533 
534     TRACE("(%p)->(%p)\n", This, p);
535 
536     return IHTMLElement2_get_onblur(&This->element.IHTMLElement2_iface, p);
537 }
538 
539 static HRESULT WINAPI HTMLAnchorElement_put_onfocus(IHTMLAnchorElement *iface, VARIANT v)
540 {
541     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
542 
543     TRACE("(%p)->()\n", This);
544 
545     return IHTMLElement2_put_onfocus(&This->element.IHTMLElement2_iface, v);
546 }
547 
548 static HRESULT WINAPI HTMLAnchorElement_get_onfocus(IHTMLAnchorElement *iface, VARIANT *p)
549 {
550     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
551 
552     TRACE("(%p)->(%p)\n", This, p);
553 
554     return IHTMLElement2_get_onfocus(&This->element.IHTMLElement2_iface, p);
555 }
556 
557 static HRESULT WINAPI HTMLAnchorElement_put_accessKey(IHTMLAnchorElement *iface, BSTR v)
558 {
559     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
560 
561     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
562 
563     return IHTMLElement2_put_accessKey(&This->element.IHTMLElement2_iface, v);
564 }
565 
566 static HRESULT WINAPI HTMLAnchorElement_get_accessKey(IHTMLAnchorElement *iface, BSTR *p)
567 {
568     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
569 
570     TRACE("(%p)->(%p)\n", This, p);
571 
572     return IHTMLElement2_get_accessKey(&This->element.IHTMLElement2_iface, p);
573 }
574 
575 static HRESULT WINAPI HTMLAnchorElement_get_protocolLong(IHTMLAnchorElement *iface, BSTR *p)
576 {
577     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
578     FIXME("(%p)->(%p)\n", This, p);
579     return E_NOTIMPL;
580 }
581 
582 static HRESULT WINAPI HTMLAnchorElement_get_mimeType(IHTMLAnchorElement *iface, BSTR *p)
583 {
584     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
585     FIXME("(%p)->(%p)\n", This, p);
586     return E_NOTIMPL;
587 }
588 
589 static HRESULT WINAPI HTMLAnchorElement_get_nameProp(IHTMLAnchorElement *iface, BSTR *p)
590 {
591     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
592     FIXME("(%p)->(%p)\n", This, p);
593     return E_NOTIMPL;
594 }
595 
596 static HRESULT WINAPI HTMLAnchorElement_put_tabIndex(IHTMLAnchorElement *iface, short v)
597 {
598     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
599 
600     TRACE("(%p)->()\n", This);
601 
602     return IHTMLElement2_put_tabIndex(&This->element.IHTMLElement2_iface, v);
603 }
604 
605 static HRESULT WINAPI HTMLAnchorElement_get_tabIndex(IHTMLAnchorElement *iface, short *p)
606 {
607     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
608 
609     TRACE("(%p)->(%p)\n", This, p);
610 
611     return IHTMLElement2_get_tabIndex(&This->element.IHTMLElement2_iface, p);
612 }
613 
614 static HRESULT WINAPI HTMLAnchorElement_focus(IHTMLAnchorElement *iface)
615 {
616     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
617 
618     TRACE("(%p)\n", This);
619 
620     return IHTMLElement2_focus(&This->element.IHTMLElement2_iface);
621 }
622 
623 static HRESULT WINAPI HTMLAnchorElement_blur(IHTMLAnchorElement *iface)
624 {
625     HTMLAnchorElement *This = impl_from_IHTMLAnchorElement(iface);
626 
627     TRACE("(%p)\n", This);
628 
629     return IHTMLElement2_blur(&This->element.IHTMLElement2_iface);
630 }
631 
632 static const IHTMLAnchorElementVtbl HTMLAnchorElementVtbl = {
633     HTMLAnchorElement_QueryInterface,
634     HTMLAnchorElement_AddRef,
635     HTMLAnchorElement_Release,
636     HTMLAnchorElement_GetTypeInfoCount,
637     HTMLAnchorElement_GetTypeInfo,
638     HTMLAnchorElement_GetIDsOfNames,
639     HTMLAnchorElement_Invoke,
640     HTMLAnchorElement_put_href,
641     HTMLAnchorElement_get_href,
642     HTMLAnchorElement_put_target,
643     HTMLAnchorElement_get_target,
644     HTMLAnchorElement_put_rel,
645     HTMLAnchorElement_get_rel,
646     HTMLAnchorElement_put_rev,
647     HTMLAnchorElement_get_rev,
648     HTMLAnchorElement_put_urn,
649     HTMLAnchorElement_get_urn,
650     HTMLAnchorElement_put_Methods,
651     HTMLAnchorElement_get_Methods,
652     HTMLAnchorElement_put_name,
653     HTMLAnchorElement_get_name,
654     HTMLAnchorElement_put_host,
655     HTMLAnchorElement_get_host,
656     HTMLAnchorElement_put_hostname,
657     HTMLAnchorElement_get_hostname,
658     HTMLAnchorElement_put_pathname,
659     HTMLAnchorElement_get_pathname,
660     HTMLAnchorElement_put_port,
661     HTMLAnchorElement_get_port,
662     HTMLAnchorElement_put_protocol,
663     HTMLAnchorElement_get_protocol,
664     HTMLAnchorElement_put_search,
665     HTMLAnchorElement_get_search,
666     HTMLAnchorElement_put_hash,
667     HTMLAnchorElement_get_hash,
668     HTMLAnchorElement_put_onblur,
669     HTMLAnchorElement_get_onblur,
670     HTMLAnchorElement_put_onfocus,
671     HTMLAnchorElement_get_onfocus,
672     HTMLAnchorElement_put_accessKey,
673     HTMLAnchorElement_get_accessKey,
674     HTMLAnchorElement_get_protocolLong,
675     HTMLAnchorElement_get_mimeType,
676     HTMLAnchorElement_get_nameProp,
677     HTMLAnchorElement_put_tabIndex,
678     HTMLAnchorElement_get_tabIndex,
679     HTMLAnchorElement_focus,
680     HTMLAnchorElement_blur
681 };
682 
683 static inline HTMLAnchorElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
684 {
685     return CONTAINING_RECORD(iface, HTMLAnchorElement, element.node);
686 }
687 
688 static HRESULT HTMLAnchorElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
689 {
690     HTMLAnchorElement *This = impl_from_HTMLDOMNode(iface);
691 
692     *ppv = NULL;
693 
694     if(IsEqualGUID(&IID_IUnknown, riid)) {
695         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
696         *ppv = &This->IHTMLAnchorElement_iface;
697     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
698         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
699         *ppv = &This->IHTMLAnchorElement_iface;
700     }else if(IsEqualGUID(&IID_IHTMLAnchorElement, riid)) {
701         TRACE("(%p)->(IID_IHTMLAnchorElement %p)\n", This, ppv);
702         *ppv = &This->IHTMLAnchorElement_iface;
703     }
704 
705     if(*ppv) {
706         IUnknown_AddRef((IUnknown*)*ppv);
707         return S_OK;
708     }
709 
710     return HTMLElement_QI(&This->element.node, riid, ppv);
711 }
712 
713 static HRESULT HTMLAnchorElement_handle_event(HTMLDOMNode *iface, DWORD eid, nsIDOMEvent *event, BOOL *prevent_default)
714 {
715     HTMLAnchorElement *This = impl_from_HTMLDOMNode(iface);
716     nsAString href_str, target_str;
717     nsresult nsres;
718 
719     if(eid == EVENTID_CLICK) {
720         nsAString_Init(&href_str, NULL);
721         nsres = nsIDOMHTMLAnchorElement_GetHref(This->nsanchor, &href_str);
722         if (NS_FAILED(nsres)) {
723             ERR("Could not get anchor href: %08x\n", nsres);
724             goto fallback;
725         }
726 
727         nsAString_Init(&target_str, NULL);
728         nsres = nsIDOMHTMLAnchorElement_GetTarget(This->nsanchor, &target_str);
729         if (NS_FAILED(nsres)) {
730             ERR("Could not get anchor target: %08x\n", nsres);
731             goto fallback;
732         }
733 
734         return handle_link_click_event(&This->element, &href_str, &target_str, event, prevent_default);
735 
736 fallback:
737         nsAString_Finish(&href_str);
738         nsAString_Finish(&target_str);
739     }
740 
741     return HTMLElement_handle_event(&This->element.node, eid, event, prevent_default);
742 }
743 
744 static void HTMLAnchorElement_traverse(HTMLDOMNode *iface, nsCycleCollectionTraversalCallback *cb)
745 {
746     HTMLAnchorElement *This = impl_from_HTMLDOMNode(iface);
747 
748     if(This->nsanchor)
749         note_cc_edge((nsISupports*)This->nsanchor, "This->nsanchor", cb);
750 }
751 
752 static void HTMLAnchorElement_unlink(HTMLDOMNode *iface)
753 {
754     HTMLAnchorElement *This = impl_from_HTMLDOMNode(iface);
755 
756     if(This->nsanchor) {
757         nsIDOMHTMLAnchorElement *nsanchor = This->nsanchor;
758 
759         This->nsanchor = NULL;
760         nsIDOMHTMLAnchorElement_Release(nsanchor);
761     }
762 }
763 
764 static const NodeImplVtbl HTMLAnchorElementImplVtbl = {
765     HTMLAnchorElement_QI,
766     HTMLElement_destructor,
767     HTMLElement_cpc,
768     HTMLElement_clone,
769     HTMLAnchorElement_handle_event,
770     HTMLElement_get_attr_col,
771     NULL,
772     NULL,
773     NULL,
774     NULL,
775     NULL,
776     NULL,
777     NULL,
778     NULL,
779     NULL,
780     HTMLAnchorElement_traverse,
781     HTMLAnchorElement_unlink
782 };
783 
784 static const tid_t HTMLAnchorElement_iface_tids[] = {
785     IHTMLAnchorElement_tid,
786     HTMLELEMENT_TIDS,
787     IHTMLUniqueName_tid,
788     0
789 };
790 
791 static dispex_static_data_t HTMLAnchorElement_dispex = {
792     NULL,
793     DispHTMLAnchorElement_tid,
794     NULL,
795     HTMLAnchorElement_iface_tids
796 };
797 
798 HRESULT HTMLAnchorElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, HTMLElement **elem)
799 {
800     HTMLAnchorElement *ret;
801     nsresult nsres;
802 
803     ret = heap_alloc_zero(sizeof(HTMLAnchorElement));
804     if(!ret)
805         return E_OUTOFMEMORY;
806 
807     ret->IHTMLAnchorElement_iface.lpVtbl = &HTMLAnchorElementVtbl;
808     ret->element.node.vtbl = &HTMLAnchorElementImplVtbl;
809 
810     HTMLElement_Init(&ret->element, doc, nselem, &HTMLAnchorElement_dispex);
811 
812     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLAnchorElement, (void**)&ret->nsanchor);
813     assert(nsres == NS_OK);
814 
815     *elem = &ret->element;
816     return S_OK;
817 }
818