winex11: Implement cursor clipping using a pointer grab.
[wine] / dlls / mshtml / persist.c
1 /*
2  * Copyright 2005 Jacek Caban
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 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "ole2.h"
32 #include "shlguid.h"
33 #include "idispids.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 #include "mshtml_private.h"
39 #include "htmlevent.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
43
44 typedef struct {
45     task_t header;
46     HTMLDocumentObj *doc;
47     BOOL set_download;
48     LPOLESTR url;
49 } download_proc_task_t;
50
51 static BOOL use_gecko_script(HTMLWindow *window)
52 {
53     DWORD zone;
54     HRESULT hres;
55
56     static const WCHAR aboutW[] = {'a','b','o','u','t',':'};
57
58     hres = IInternetSecurityManager_MapUrlToZone(window->secmgr, window->url, &zone, 0);
59     if(FAILED(hres)) {
60         WARN("Could not map %s to zone: %08x\n", debugstr_w(window->url), hres);
61         return TRUE;
62     }
63
64     TRACE("zone %d\n", zone);
65     return zone != URLZONE_LOCAL_MACHINE && zone != URLZONE_TRUSTED
66         && strncmpiW(aboutW, window->url, sizeof(aboutW)/sizeof(WCHAR));
67 }
68
69 void set_current_mon(HTMLWindow *This, IMoniker *mon)
70 {
71     HRESULT hres;
72
73     if(This->mon) {
74         IMoniker_Release(This->mon);
75         This->mon = NULL;
76     }
77
78     if(This->url) {
79         CoTaskMemFree(This->url);
80         This->url = NULL;
81     }
82
83     if(!mon)
84         return;
85
86     IMoniker_AddRef(mon);
87     This->mon = mon;
88
89     hres = IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
90     if(FAILED(hres))
91         WARN("GetDisplayName failed: %08x\n", hres);
92
93     set_script_mode(This, use_gecko_script(This) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT);
94 }
95
96 static void set_progress_proc(task_t *_task)
97 {
98     docobj_task_t *task = (docobj_task_t*)_task;
99     IOleCommandTarget *olecmd = NULL;
100     HTMLDocumentObj *doc = task->doc;
101     HRESULT hres;
102
103     TRACE("(%p)\n", doc);
104
105     if(doc->client)
106         IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
107
108     if(olecmd) {
109         VARIANT progress_max, progress;
110
111         V_VT(&progress_max) = VT_I4;
112         V_I4(&progress_max) = 0; /* FIXME */
113         IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETPROGRESSMAX, OLECMDEXECOPT_DONTPROMPTUSER,
114                                &progress_max, NULL);
115
116         V_VT(&progress) = VT_I4;
117         V_I4(&progress) = 0; /* FIXME */
118         IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETPROGRESSPOS, OLECMDEXECOPT_DONTPROMPTUSER,
119                                &progress, NULL);
120         IOleCommandTarget_Release(olecmd);
121     }
122
123     if(doc->usermode == EDITMODE && doc->hostui) {
124         DOCHOSTUIINFO hostinfo;
125
126         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
127         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
128         hres = IDocHostUIHandler_GetHostInfo(doc->hostui, &hostinfo);
129         if(SUCCEEDED(hres))
130             /* FIXME: use hostinfo */
131             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
132                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
133                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
134     }
135 }
136
137 static void set_downloading_proc(task_t *_task)
138 {
139     download_proc_task_t *task = (download_proc_task_t*)_task;
140     HTMLDocumentObj *doc = task->doc;
141     IOleCommandTarget *olecmd;
142     HRESULT hres;
143
144     TRACE("(%p)\n", doc);
145
146     set_statustext(doc, IDS_STATUS_DOWNLOADINGFROM, task->url);
147     CoTaskMemFree(task->url);
148
149     if(!doc->client)
150         return;
151
152     if(task->set_download) {
153         hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
154         if(SUCCEEDED(hres)) {
155             VARIANT var;
156
157             V_VT(&var) = VT_I4;
158             V_I4(&var) = 1;
159
160             IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETDOWNLOADSTATE,
161                     OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
162             IOleCommandTarget_Release(olecmd);
163         }
164
165         doc->download_state = 1;
166     }
167
168     if(doc->view_sink)
169         IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
170
171     if(doc->hostui) {
172         IDropTarget *drop_target = NULL;
173
174         hres = IDocHostUIHandler_GetDropTarget(doc->hostui, NULL /* FIXME */, &drop_target);
175         if(drop_target) {
176             FIXME("Use IDropTarget\n");
177             IDropTarget_Release(drop_target);
178         }
179     }
180 }
181
182 HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, nsChannelBSC *async_bsc, BOOL set_download)
183 {
184     nsChannelBSC *bscallback;
185     docobj_task_t *task;
186     download_proc_task_t *download_task;
187     nsWineURI *nsuri;
188     LPOLESTR url;
189     HRESULT hres;
190
191     hres = IMoniker_GetDisplayName(mon, pibc, NULL, &url);
192     if(FAILED(hres)) {
193         WARN("GetDiaplayName failed: %08x\n", hres);
194         return hres;
195     }
196
197     TRACE("got url: %s\n", debugstr_w(url));
198
199     if(This->doc_obj->client) {
200         VARIANT silent, offline;
201
202         hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_SILENT, &silent);
203         if(SUCCEEDED(hres)) {
204             if(V_VT(&silent) != VT_BOOL)
205                 WARN("V_VT(silent) = %d\n", V_VT(&silent));
206             else if(V_BOOL(&silent))
207                 FIXME("silent == true\n");
208         }
209
210         hres = get_client_disp_property(This->doc_obj->client,
211                 DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &offline);
212         if(SUCCEEDED(hres)) {
213             if(V_VT(&offline) != VT_BOOL)
214                 WARN("V_VT(offline) = %d\n", V_VT(&offline));
215             else if(V_BOOL(&offline))
216                 FIXME("offline == true\n");
217         }
218     }
219
220     if(This->window->mon) {
221         update_doc(This, UPDATE_TITLE|UPDATE_UI);
222     }else {
223         update_doc(This, UPDATE_TITLE);
224         set_current_mon(This->window, mon);
225     }
226
227     set_ready_state(This->window, READYSTATE_LOADING);
228
229     if(This->doc_obj->client) {
230         IOleCommandTarget *cmdtrg = NULL;
231
232         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
233                 (void**)&cmdtrg);
234         if(SUCCEEDED(hres)) {
235             VARIANT var, out;
236
237             if(!async_bsc) {
238                 V_VT(&var) = VT_I4;
239                 V_I4(&var) = 0;
240                 IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
241             }else {
242                 V_VT(&var) = VT_UNKNOWN;
243                 V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
244                 V_VT(&out) = VT_EMPTY;
245                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 63, 0, &var, &out);
246                 if(SUCCEEDED(hres))
247                     VariantClear(&out);
248             }
249
250             IOleCommandTarget_Release(cmdtrg);
251         }
252     }
253
254     hres = create_doc_uri(This->window, url, &nsuri);
255
256     if(SUCCEEDED(hres))
257     {
258         if(async_bsc) {
259             bscallback = async_bsc;
260         }else {
261             hres = create_channelbsc(mon, NULL, NULL, 0, &bscallback);
262         }
263     }
264
265     if(SUCCEEDED(hres))
266     {
267         remove_target_tasks(This->task_magic);
268         abort_document_bindings(This->doc_node);
269
270         hres = load_nsuri(This->window, nsuri, bscallback, LOAD_INITIAL_DOCUMENT_URI);
271         nsISupports_Release((nsISupports*)nsuri); /* FIXME */
272         if(SUCCEEDED(hres))
273             set_window_bscallback(This->window, bscallback);
274         if(bscallback != async_bsc)
275             IUnknown_Release((IUnknown*)bscallback);
276     }
277
278     if(FAILED(hres))
279     {
280         CoTaskMemFree(url);
281         return hres;
282     }
283
284     HTMLDocument_LockContainer(This->doc_obj, TRUE);
285
286     if(This->doc_obj->frame) {
287         task = heap_alloc(sizeof(docobj_task_t));
288         task->doc = This->doc_obj;
289         push_task(&task->header, set_progress_proc, This->doc_obj->basedoc.task_magic);
290     }
291
292     download_task = heap_alloc(sizeof(download_proc_task_t));
293     download_task->doc = This->doc_obj;
294     download_task->set_download = set_download;
295     download_task->url = url;
296     push_task(&download_task->header, set_downloading_proc, This->doc_obj->basedoc.task_magic);
297
298     return S_OK;
299 }
300
301 void set_ready_state(HTMLWindow *window, READYSTATE readystate)
302 {
303     window->readystate = readystate;
304
305     if(window->doc_obj && window->doc_obj->basedoc.window == window)
306         call_property_onchanged(&window->doc_obj->basedoc.cp_propnotif, DISPID_READYSTATE);
307
308     fire_event(window->doc, EVENTID_READYSTATECHANGE, FALSE, window->doc->node.nsnode, NULL);
309
310     if(window->frame_element)
311         fire_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE,
312                    TRUE, window->frame_element->element.node.nsnode, NULL);
313 }
314
315 static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
316 {
317     nsIDOMNode *nsnode;
318     LPCWSTR strw;
319     nsAString nsstr;
320     nsresult nsres;
321
322     if(!This->nsdoc) {
323         WARN("NULL nsdoc\n");
324         return E_UNEXPECTED;
325     }
326
327     nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
328     if(NS_FAILED(nsres)) {
329         ERR("Could not get nsIDOMNode failed: %08x\n", nsres);
330         return E_FAIL;
331     }
332
333     nsAString_Init(&nsstr, NULL);
334     nsnode_to_nsstring(nsnode, &nsstr);
335     nsIDOMNode_Release(nsnode);
336
337     nsAString_GetData(&nsstr, &strw);
338     TRACE("%s\n", debugstr_w(strw));
339
340     *str = heap_strdupWtoA(strw);
341
342     nsAString_Finish(&nsstr);
343
344     return S_OK;
345 }
346
347
348 /**********************************************************
349  * IPersistMoniker implementation
350  */
351
352 static inline HTMLDocument *impl_from_IPersistMoniker(IPersistMoniker *iface)
353 {
354     return CONTAINING_RECORD(iface, HTMLDocument, IPersistMoniker_iface);
355 }
356
357 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid, void **ppv)
358 {
359     HTMLDocument *This = impl_from_IPersistMoniker(iface);
360     return htmldoc_query_interface(This, riid, ppv);
361 }
362
363 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
364 {
365     HTMLDocument *This = impl_from_IPersistMoniker(iface);
366     return htmldoc_addref(This);
367 }
368
369 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
370 {
371     HTMLDocument *This = impl_from_IPersistMoniker(iface);
372     return htmldoc_release(This);
373 }
374
375 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
376 {
377     HTMLDocument *This = impl_from_IPersistMoniker(iface);
378     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
379 }
380
381 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
382 {
383     HTMLDocument *This = impl_from_IPersistMoniker(iface);
384
385     TRACE("(%p)\n", This);
386
387     return IPersistStreamInit_IsDirty(&This->IPersistStreamInit_iface);
388 }
389
390 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
391         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
392 {
393     HTMLDocument *This = impl_from_IPersistMoniker(iface);
394     HRESULT hres;
395
396     TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
397
398     if(pibc) {
399         IUnknown *unk = NULL;
400
401         /* FIXME:
402          * Use params:
403          * "__PrecreatedObject"
404          * "BIND_CONTEXT_PARAM"
405          * "__HTMLLOADOPTIONS"
406          * "__DWNBINDINFO"
407          * "URL Context"
408          * "_ITransData_Object_"
409          * "_EnumFORMATETC_"
410          */
411
412         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
413         if(unk) {
414             IOleClientSite *client = NULL;
415
416             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
417             if(SUCCEEDED(hres)) {
418                 TRACE("Got client site %p\n", client);
419                 IOleObject_SetClientSite(&This->IOleObject_iface, client);
420                 IOleClientSite_Release(client);
421             }
422
423             IUnknown_Release(unk);
424         }
425     }
426
427     hres = set_moniker(This, pimkName, pibc, NULL, TRUE);
428     if(FAILED(hres))
429         return hres;
430
431     return start_binding(This->window, NULL, (BSCallback*)This->window->bscallback, pibc);
432 }
433
434 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
435         LPBC pbc, BOOL fRemember)
436 {
437     HTMLDocument *This = impl_from_IPersistMoniker(iface);
438     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
443 {
444     HTMLDocument *This = impl_from_IPersistMoniker(iface);
445     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
446     return E_NOTIMPL;
447 }
448
449 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
450 {
451     HTMLDocument *This = impl_from_IPersistMoniker(iface);
452
453     TRACE("(%p)->(%p)\n", This, ppimkName);
454
455     if(!This->window || !This->window->mon)
456         return E_UNEXPECTED;
457
458     IMoniker_AddRef(This->window->mon);
459     *ppimkName = This->window->mon;
460     return S_OK;
461 }
462
463 static const IPersistMonikerVtbl PersistMonikerVtbl = {
464     PersistMoniker_QueryInterface,
465     PersistMoniker_AddRef,
466     PersistMoniker_Release,
467     PersistMoniker_GetClassID,
468     PersistMoniker_IsDirty,
469     PersistMoniker_Load,
470     PersistMoniker_Save,
471     PersistMoniker_SaveCompleted,
472     PersistMoniker_GetCurMoniker
473 };
474
475 /**********************************************************
476  * IMonikerProp implementation
477  */
478
479 static inline HTMLDocument *impl_from_IMonikerProp(IMonikerProp *iface)
480 {
481     return CONTAINING_RECORD(iface, HTMLDocument, IMonikerProp_iface);
482 }
483
484 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppv)
485 {
486     HTMLDocument *This = impl_from_IMonikerProp(iface);
487     return htmldoc_query_interface(This, riid, ppv);
488 }
489
490 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
491 {
492     HTMLDocument *This = impl_from_IMonikerProp(iface);
493     return htmldoc_addref(This);
494 }
495
496 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
497 {
498     HTMLDocument *This = impl_from_IMonikerProp(iface);
499     return htmldoc_release(This);
500 }
501
502 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
503 {
504     HTMLDocument *This = impl_from_IMonikerProp(iface);
505
506     TRACE("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
507
508     switch(mkp) {
509     case MIMETYPEPROP:
510         heap_free(This->doc_obj->mime);
511         This->doc_obj->mime = heap_strdupW(val);
512         break;
513
514     case CLASSIDPROP:
515         break;
516
517     default:
518         FIXME("mkp %d\n", mkp);
519         return E_NOTIMPL;
520     }
521
522     return S_OK;
523 }
524
525 static const IMonikerPropVtbl MonikerPropVtbl = {
526     MonikerProp_QueryInterface,
527     MonikerProp_AddRef,
528     MonikerProp_Release,
529     MonikerProp_PutProperty
530 };
531
532 /**********************************************************
533  * IPersistFile implementation
534  */
535
536 static inline HTMLDocument *impl_from_IPersistFile(IPersistFile *iface)
537 {
538     return CONTAINING_RECORD(iface, HTMLDocument, IPersistFile_iface);
539 }
540
541 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppv)
542 {
543     HTMLDocument *This = impl_from_IPersistFile(iface);
544     return htmldoc_query_interface(This, riid, ppv);
545 }
546
547 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
548 {
549     HTMLDocument *This = impl_from_IPersistFile(iface);
550     return htmldoc_addref(This);
551 }
552
553 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
554 {
555     HTMLDocument *This = impl_from_IPersistFile(iface);
556     return htmldoc_release(This);
557 }
558
559 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
560 {
561     HTMLDocument *This = impl_from_IPersistFile(iface);
562
563     TRACE("(%p)->(%p)\n", This, pClassID);
564
565     if(!pClassID)
566         return E_INVALIDARG;
567
568     *pClassID = CLSID_HTMLDocument;
569     return S_OK;
570 }
571
572 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
573 {
574     HTMLDocument *This = impl_from_IPersistFile(iface);
575
576     TRACE("(%p)\n", This);
577
578     return IPersistStreamInit_IsDirty(&This->IPersistStreamInit_iface);
579 }
580
581 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
582 {
583     HTMLDocument *This = impl_from_IPersistFile(iface);
584     FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
585     return E_NOTIMPL;
586 }
587
588 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
589 {
590     HTMLDocument *This = impl_from_IPersistFile(iface);
591     char *str;
592     DWORD written=0;
593     HANDLE file;
594     HRESULT hres;
595
596     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
597
598     file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
599                        FILE_ATTRIBUTE_NORMAL, NULL);
600     if(file == INVALID_HANDLE_VALUE) {
601         WARN("Could not create file: %u\n", GetLastError());
602         return E_FAIL;
603     }
604
605     hres = get_doc_string(This->doc_node, &str);
606     if(SUCCEEDED(hres))
607         WriteFile(file, str, strlen(str), &written, NULL);
608
609     CloseHandle(file);
610     return hres;
611 }
612
613 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
614 {
615     HTMLDocument *This = impl_from_IPersistFile(iface);
616     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
617     return E_NOTIMPL;
618 }
619
620 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
621 {
622     HTMLDocument *This = impl_from_IPersistFile(iface);
623     FIXME("(%p)->(%p)\n", This, pszFileName);
624     return E_NOTIMPL;
625 }
626
627 static const IPersistFileVtbl PersistFileVtbl = {
628     PersistFile_QueryInterface,
629     PersistFile_AddRef,
630     PersistFile_Release,
631     PersistFile_GetClassID,
632     PersistFile_IsDirty,
633     PersistFile_Load,
634     PersistFile_Save,
635     PersistFile_SaveCompleted,
636     PersistFile_GetCurFile
637 };
638
639 static inline HTMLDocument *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
640 {
641     return CONTAINING_RECORD(iface, HTMLDocument, IPersistStreamInit_iface);
642 }
643
644 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
645                                                        REFIID riid, void **ppv)
646 {
647     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
648     return htmldoc_query_interface(This, riid, ppv);
649 }
650
651 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
652 {
653     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
654     return htmldoc_addref(This);
655 }
656
657 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
658 {
659     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
660     return htmldoc_release(This);
661 }
662
663 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
664 {
665     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
666     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
667 }
668
669 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
670 {
671     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
672
673     TRACE("(%p)\n", This);
674
675     if(This->doc_obj->usermode == EDITMODE)
676         return editor_is_dirty(This);
677
678     return S_FALSE;
679 }
680
681 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
682 {
683     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
684     IMoniker *mon;
685     HRESULT hres;
686
687     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
688
689     TRACE("(%p)->(%p)\n", This, pStm);
690
691     hres = CreateURLMoniker(NULL, about_blankW, &mon);
692     if(FAILED(hres)) {
693         WARN("CreateURLMoniker failed: %08x\n", hres);
694         return hres;
695     }
696
697     hres = set_moniker(This, mon, NULL, NULL, TRUE);
698     IMoniker_Release(mon);
699     if(FAILED(hres))
700         return hres;
701
702     return channelbsc_load_stream(This->window->bscallback, pStm);
703 }
704
705 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
706                                              BOOL fClearDirty)
707 {
708     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
709     char *str;
710     DWORD written=0;
711     HRESULT hres;
712
713     TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
714
715     hres = get_doc_string(This->doc_node, &str);
716     if(FAILED(hres))
717         return hres;
718
719     hres = IStream_Write(pStm, str, strlen(str), &written);
720     if(FAILED(hres))
721         FIXME("Write failed: %08x\n", hres);
722
723     heap_free(str);
724
725     if(fClearDirty)
726         set_dirty(This, VARIANT_FALSE);
727
728     return S_OK;
729 }
730
731 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
732                                                    ULARGE_INTEGER *pcbSize)
733 {
734     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
735     FIXME("(%p)->(%p)\n", This, pcbSize);
736     return E_NOTIMPL;
737 }
738
739 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
740 {
741     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
742     IMoniker *mon;
743     HRESULT hres;
744
745     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
746
747     TRACE("(%p)\n", This);
748
749     hres = CreateURLMoniker(NULL, about_blankW, &mon);
750     if(FAILED(hres)) {
751         WARN("CreateURLMoniker failed: %08x\n", hres);
752         return hres;
753     }
754
755     hres = set_moniker(This, mon, NULL, NULL, FALSE);
756     IMoniker_Release(mon);
757     if(FAILED(hres))
758         return hres;
759
760     return channelbsc_load_stream(This->window->bscallback, NULL);
761 }
762
763 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
764     PersistStreamInit_QueryInterface,
765     PersistStreamInit_AddRef,
766     PersistStreamInit_Release,
767     PersistStreamInit_GetClassID,
768     PersistStreamInit_IsDirty,
769     PersistStreamInit_Load,
770     PersistStreamInit_Save,
771     PersistStreamInit_GetSizeMax,
772     PersistStreamInit_InitNew
773 };
774
775 /**********************************************************
776  * IPersistHistory implementation
777  */
778
779 static inline HTMLDocument *impl_from_IPersistHistory(IPersistHistory *iface)
780 {
781     return CONTAINING_RECORD(iface, HTMLDocument, IPersistHistory_iface);
782 }
783
784 static HRESULT WINAPI PersistHistory_QueryInterface(IPersistHistory *iface, REFIID riid, void **ppv)
785 {
786     HTMLDocument *This = impl_from_IPersistHistory(iface);
787     return htmldoc_query_interface(This, riid, ppv);
788 }
789
790 static ULONG WINAPI PersistHistory_AddRef(IPersistHistory *iface)
791 {
792     HTMLDocument *This = impl_from_IPersistHistory(iface);
793     return htmldoc_addref(This);
794 }
795
796 static ULONG WINAPI PersistHistory_Release(IPersistHistory *iface)
797 {
798     HTMLDocument *This = impl_from_IPersistHistory(iface);
799     return htmldoc_release(This);
800 }
801
802 static HRESULT WINAPI PersistHistory_GetClassID(IPersistHistory *iface, CLSID *pClassID)
803 {
804     HTMLDocument *This = impl_from_IPersistHistory(iface);
805     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
806 }
807
808 static HRESULT WINAPI PersistHistory_LoadHistory(IPersistHistory *iface, IStream *pStream, IBindCtx *pbc)
809 {
810     HTMLDocument *This = impl_from_IPersistHistory(iface);
811     FIXME("(%p)->(%p %p)\n", This, pStream, pbc);
812     return E_NOTIMPL;
813 }
814
815 static HRESULT WINAPI PersistHistory_SaveHistory(IPersistHistory *iface, IStream *pStream)
816 {
817     HTMLDocument *This = impl_from_IPersistHistory(iface);
818     FIXME("(%p)->(%p)\n", This, pStream);
819     return E_NOTIMPL;
820 }
821
822 static HRESULT WINAPI PersistHistory_SetPositionCookie(IPersistHistory *iface, DWORD dwPositioncookie)
823 {
824     HTMLDocument *This = impl_from_IPersistHistory(iface);
825     FIXME("(%p)->(%x)\n", This, dwPositioncookie);
826     return E_NOTIMPL;
827 }
828
829 static HRESULT WINAPI PersistHistory_GetPositionCookie(IPersistHistory *iface, DWORD *pdwPositioncookie)
830 {
831     HTMLDocument *This = impl_from_IPersistHistory(iface);
832     FIXME("(%p)->(%p)\n", This, pdwPositioncookie);
833     return E_NOTIMPL;
834 }
835
836 static const IPersistHistoryVtbl PersistHistoryVtbl = {
837     PersistHistory_QueryInterface,
838     PersistHistory_AddRef,
839     PersistHistory_Release,
840     PersistHistory_GetClassID,
841     PersistHistory_LoadHistory,
842     PersistHistory_SaveHistory,
843     PersistHistory_SetPositionCookie,
844     PersistHistory_GetPositionCookie
845 };
846
847 void HTMLDocument_Persist_Init(HTMLDocument *This)
848 {
849     This->IPersistMoniker_iface.lpVtbl = &PersistMonikerVtbl;
850     This->IPersistFile_iface.lpVtbl = &PersistFileVtbl;
851     This->IMonikerProp_iface.lpVtbl = &MonikerPropVtbl;
852     This->IPersistStreamInit_iface.lpVtbl = &PersistStreamInitVtbl;
853     This->IPersistHistory_iface.lpVtbl = &PersistHistoryVtbl;
854 }