From: Gabriel Ivăncescu gabrielopcode@gmail.com
Native modes IE10 and up implement XML documents as children of the DocumentPrototype, which have standard IHTMLDocument interfaces. But previous modes do not, but instead have the IXMLDOMDocument interface (which suggests it uses msxml like now).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 25 ++++++++++++++++++++++--- dlls/mshtml/htmlwindow.c | 2 +- dlls/mshtml/mshtml_private.h | 5 ++++- dlls/mshtml/omnavigator.c | 2 +- dlls/mshtml/tests/documentmode.js | 6 +++++- dlls/mshtml/tests/xhr.js | 22 ++++++++++++++++++++++ dlls/mshtml/tests/xmlhttprequest.c | 15 +++++++++++++++ dlls/mshtml/xmlhttprequest.c | 14 ++++++++++++++ 8 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 7255e8d9ec3..b99686dd3a5 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -39,6 +39,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
+static dispex_static_data_t *const dispex_from_document_type[] = { + [DOCTYPE_HTML] = &HTMLDocument_dispex, + [DOCTYPE_XHTML] = &XMLDocument_dispex, + [DOCTYPE_XML] = &XMLDocument_dispex, + [DOCTYPE_SVG] = &XMLDocument_dispex, +}; + static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *doc_node, HTMLDocumentNode **ret);
HRESULT get_doc_elem_by_id(HTMLDocumentNode *doc, const WCHAR *id, HTMLElement **ret) @@ -5634,7 +5641,7 @@ static HTMLInnerWindow *HTMLDocumentNode_get_script_global(DispatchEx *dispex, d if(This->node.vtbl != &HTMLDocumentNodeImplVtbl) *dispex_data = &DocumentFragment_dispex; else - *dispex_data = This->document_mode < COMPAT_MODE_IE11 ? &Document_dispex : &HTMLDocument_dispex; + *dispex_data = This->document_mode < COMPAT_MODE_IE11 ? &Document_dispex : dispex_from_document_type[This->doc_type]; return This->script_global; }
@@ -5870,6 +5877,17 @@ dispex_static_data_t HTMLDocument_dispex = { .min_compat_mode = COMPAT_MODE_IE11, };
+dispex_static_data_t XMLDocument_dispex = { + .id = OBJID_XMLDocument, + .prototype_id = OBJID_Document, + .vtbl = &HTMLDocument_event_target_vtbl.dispex_vtbl, + .disp_tid = DispHTMLDocument_tid, + .iface_tids = HTMLDocumentNode_iface_tids, + .init_info = HTMLDocumentNode_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_FILL, + .min_compat_mode = COMPAT_MODE_IE11, +}; + static HTMLDocumentNode *alloc_doc_node(HTMLDocumentObj *doc_obj, HTMLInnerWindow *window, HTMLInnerWindow *script_global) { HTMLDocumentNode *doc; @@ -5919,7 +5937,7 @@ static HTMLDocumentNode *alloc_doc_node(HTMLDocumentObj *doc_obj, HTMLInnerWindo }
HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLInnerWindow *window, - HTMLInnerWindow *script_global, compat_mode_t parent_mode, HTMLDocumentNode **ret) + HTMLInnerWindow *script_global, document_type_t doc_type, compat_mode_t parent_mode, HTMLDocumentNode **ret) { HTMLDocumentObj *doc_obj = browser->doc; HTMLDocumentNode *doc; @@ -5927,6 +5945,7 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc = alloc_doc_node(doc_obj, window, script_global); if(!doc) return E_OUTOFMEMORY; + doc->doc_type = doc_type;
if(parent_mode >= COMPAT_MODE_IE9) { TRACE("using parent mode %u\n", parent_mode); @@ -5946,7 +5965,7 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc->html_document = NULL; }
- HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, &HTMLDocument_dispex); + HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, dispex_from_document_type[doc_type]);
init_document_mutation(doc); doc_init_events(doc); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index c608ab1c881..8428fc1d31d 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -4527,7 +4527,7 @@ HRESULT update_window_doc(HTMLInnerWindow *window) if(outer_window->parent) parent_mode = outer_window->parent->base.inner_window->doc->document_mode;
- hres = create_document_node(nsdoc, outer_window->browser, window, window, parent_mode, &window->doc); + hres = create_document_node(nsdoc, outer_window->browser, window, window, DOCTYPE_HTML, parent_mode, &window->doc); nsIDOMDocument_Release(nsdoc); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index de1fe07ab21..2f06b504b52 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -510,6 +510,7 @@ typedef struct { X(TextRange) \ X(UIEvent) \ X(Window) \ + X(XMLDocument) \ X(XMLHttpRequest)
typedef enum { @@ -1094,6 +1095,7 @@ struct HTMLFrameBase {
typedef struct nsDocumentEventListener nsDocumentEventListener;
+/* NOTE: Update arrays at top of htmldoc.c if you change this */ typedef enum { DOCTYPE_INVALID = -1, DOCTYPE_HTML, @@ -1157,6 +1159,7 @@ struct HTMLDocumentNode { unsigned int content_ready : 1; unsigned int unload_sent : 1;
+ document_type_t doc_type; IHTMLDOMImplementation *dom_implementation; IHTMLNamespaceCollection *namespaces;
@@ -1183,7 +1186,7 @@ HRESULT HTMLDocument_Create(IUnknown*,REFIID,void**); HRESULT MHTMLDocument_Create(IUnknown*,REFIID,void**); HRESULT HTMLLoadOptions_Create(IUnknown*,REFIID,void**); HRESULT create_document_node(nsIDOMDocument*,GeckoBrowser*,HTMLInnerWindow*,HTMLInnerWindow*, - compat_mode_t,HTMLDocumentNode**); + document_type_t,compat_mode_t,HTMLDocumentNode**); HRESULT create_doctype_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**);
HRESULT create_outer_window(GeckoBrowser*,mozIDOMWindowProxy*,HTMLOuterWindow*,HTMLOuterWindow**); diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 8ba88200c3c..ee17332e27a 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -159,7 +159,7 @@ static HRESULT WINAPI HTMLDOMImplementation2_createHTMLDocument(IHTMLDOMImplemen
compat_mode = dispex_compat_mode(&This->dispex); hres = create_document_node(doc, This->doc->browser, NULL, This->doc->script_global, - compat_mode, &new_document_node); + DOCTYPE_HTML, compat_mode, &new_document_node); nsIDOMDocument_Release(doc); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 6809b957b2f..17b4919457d 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -981,6 +981,7 @@ sync_test("window_props", function() { test_exposed("matchMedia", v >= 10); test_exposed("Document", v >= 9); test_exposed("HTMLDocument", v === 8 || v >= 11, v === 8); + test_exposed("XMLDocument", v >= 11); test_exposed("DOMParser", v >= 9); test_exposed("MutationObserver", v >= 11); test_exposed("PageTransitionEvent", v >= 11); @@ -3868,6 +3869,7 @@ sync_test("prototypes", function() { else { check(document, HTMLDocument.prototype, "html document"); check(HTMLDocument.prototype, Document.prototype, "html document prototype"); + check(XMLDocument.prototype, Document.prototype, "xml document prototype"); } check(Document.prototype, Node.prototype, "document prototype"); check(window, Window.prototype, "window"); @@ -4412,6 +4414,8 @@ sync_test("prototype props", function() { check(StyleSheet, [ "disabled", "href", "media", "ownerNode", "parentStyleSheet", "title", "type" ]); check(Text, [ "removeNode", "replaceNode", "replaceWholeText", "splitText", "swapNode", "wholeText" ], [ "replaceWholeText", "wholeText" ]); check(UIEvent, [ "detail", "initUIEvent", "view" ], null, [ "deviceSessionId" ]); + if(v >= 11) + check(XMLDocument, []); });
sync_test("constructors", function() { @@ -4585,7 +4589,7 @@ async_test("window own props", function() { ["TrackEvent",10], ["TransitionEvent",10], "TreeWalker", ["Uint16Array",10], ["Uint32Array",10], ["Uint8Array",10], ["Uint8ClampedArray",11], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], ["WebGLFramebuffer",11], ["WebGLObject",11], ["WebGLProgram",11], ["WebGLRenderbuffer",11], ["WebGLRenderingContext",11], ["WebGLShader",11], ["WebGLShaderPrecisionFormat",11], ["WebGLTexture",11], ["WebGLUniformLocation",11], ["WEBGL_compressed_texture_s3tc",11], - ["WEBGL_debug_renderer_info",11], ["WebSocket",10], "WheelEvent", ["Worker",10], ["XDomainRequest",9,10], ["XMLDocument",11], ["XMLHttpRequestEventTarget",10], "XMLSerializer" + ["WEBGL_debug_renderer_info",11], ["WebSocket",10], "WheelEvent", ["Worker",10], ["XDomainRequest",9,10], ["XMLHttpRequestEventTarget",10], "XMLSerializer" ]); next_test(); } diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index cc543e7cec8..46aed46624c 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -22,6 +22,7 @@ var xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<a name="test">wine</a> async_test("async_xhr", function() { var xhr = new XMLHttpRequest(); var complete_cnt = 0, loadstart = false; + var v = document.documentMode;
xhr.onreadystatechange = function() { if(xhr.readyState != 4) @@ -30,6 +31,26 @@ async_test("async_xhr", function() { ok(xhr.responseText === xml, "unexpected responseText " + xhr.responseText); ok(xhr.responseXML !== null, "unexpected null responseXML");
+ var x = xhr.responseXML, r = Object.prototype.toString.call(x); + ok(r === (v < 10 ? "[object Object]" : (v < 11 ? "[object Document]" : "[object XMLDocument]")), + "XML document Object.toString = " + r); + + r = Object.getPrototypeOf(x); + if(v < 10) + ok(r === null, "prototype of returned XML document = " + r); + else if(v < 11) + ok(r === window.Document.prototype, "prototype of returned XML document = " + r); + else + ok(r === window.XMLDocument.prototype, "prototype of returned XML document = " + r); + + if(v < 10) { + ok(!("anchors" in x), "anchors is in returned XML document"); + ok(Object.prototype.hasOwnProperty.call(x, "createElement"), "createElement not a prop of returned XML document"); + }else { + ok("anchors" in x, "anchors not in returned XML document"); + ok(!x.hasOwnProperty("createElement"), "createElement is a prop of returned XML document"); + } + if(complete_cnt++ && !("onloadend" in xhr)) next_test(); } @@ -229,6 +250,7 @@ async_test("content_types", function() { var xml_types = [ "text/xmL", "apPliCation/xml", + "application/xHtml+xml", "image/SvG+xml", "Wine/Test+xml", "++Xml", diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 6226461a502..44132160520 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -519,10 +519,14 @@ static void _set_request_header(unsigned line, IHTMLXMLHttpRequest *xhr, const W static void test_responseXML(const WCHAR *expect_text) { IDispatch *disp; + IHTMLDocument2 *html_doc; IXMLDOMDocument *xmldom; IObjectSafety *safety; + IHTMLDOMNode *node; DWORD enabled = 0, supported = 0; + DISPID dispid; HRESULT hres; + BSTR str;
disp = NULL; hres = IHTMLXMLHttpRequest_get_responseXML(xhr, &disp); @@ -545,6 +549,17 @@ static void test_responseXML(const WCHAR *expect_text) "Expected enabled: (INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_SECURITY_MANAGER), got 0x%08lx\n", enabled); IObjectSafety_Release(safety);
+ hres = IXMLDOMDocument_QueryInterface(xmldom, &IID_IHTMLDOMNode, (void**)&node); + ok(hres == E_NOINTERFACE, "QueryInterface(IHTMLDOMNode) returned: %08lx\n", hres); + + hres = IXMLDOMDocument_QueryInterface(xmldom, &IID_IHTMLDocument2, (void**)&html_doc); + ok(hres == E_NOINTERFACE, "QueryInterface(IHTMLDocument2) returned: %08lx\n", hres); + + str = SysAllocString(L"anchors"); + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &str, 1, LOCALE_USER_DEFAULT, &dispid); + ok(hres == DISP_E_UNKNOWNNAME, "GetIDsOfNames("anchors") returned: %08lx\n", hres); + SysFreeString(str); + if(!expect_text) test_illegal_xml(xmldom);
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 3097792c620..23e5db46070 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -576,6 +576,7 @@ static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *if }
if(dispex_compat_mode(&This->event_target.dispex) >= COMPAT_MODE_IE10) { + HTMLDocumentNode *doc; nsIDOMDocument *nsdoc; nsresult nsres;
@@ -586,7 +587,20 @@ static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *if *p = NULL; return S_OK; } + + if(!This->window->base.outer_window || !This->window->base.outer_window->browser) + hres = E_UNEXPECTED; + else + hres = create_document_node(nsdoc, This->window->base.outer_window->browser, NULL, This->window, + DOCTYPE_XML, dispex_compat_mode(&This->window->event_target.dispex), &doc); nsIDOMDocument_Release(nsdoc); + if(FAILED(hres)) + return hres; + + /* make sure dispex info is initialized */ + dispex_compat_mode(&doc->node.event_target.dispex); + *p = (IDispatch*)&doc->IHTMLDocument2_iface; + return S_OK; }
hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&xmldoc);