-- v3: mshtml: Implement DOMParser's parseFromString. mshtml: Implement anchors prop for XML documents. mshtml: Fallback to text/xml for unknown content types in get_mimeType. mshtml: Use Gecko's responseXML to create the XML document in IE10 and up. mshtml: Implement DOMParser constructor and instance object.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mshtml_private.h | 3 + dlls/mshtml/omnavigator.c | 125 ++++++++++++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 11 ++- dlls/mshtml/tests/es5.js | 11 +++ 4 files changed, 148 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5c81a74b16e..50f147531d1 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -108,6 +108,7 @@ struct constructor; XDIID(DispDOMStorageEvent) \ XDIID(DispDOMUIEvent) \ XDIID(DispDOMDocumentType) \ + XDIID(DispDOMParser) \ XDIID(DispHTMLAnchorElement) \ XDIID(DispHTMLAreaElement) \ XDIID(DispHTMLAttributeCollection) \ @@ -172,6 +173,7 @@ struct constructor; XIID(IDOMStorageEvent) \ XIID(IDOMUIEvent) \ XIID(IDOMDocumentType) \ + XIID(IDOMParser) \ XIID(IDocumentEvent) \ XIID(IDocumentRange) \ XIID(IDocumentSelector) \ @@ -429,6 +431,7 @@ typedef struct { X(Console) \ X(CustomEvent) \ X(DOMImplementation) \ + X(DOMParser) \ X(DOMTokenList) \ X(Document) \ X(DocumentFragment) \ diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 660510fc3f2..c65fb675372 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -269,6 +269,131 @@ void detach_dom_implementation(IHTMLDOMImplementation *iface) dom_implementation->doc = NULL; }
+struct dom_parser { + DispatchEx dispex; + IDOMParser IDOMParser_iface; +}; + +static inline struct dom_parser *impl_from_IDOMParser(IDOMParser *iface) +{ + return CONTAINING_RECORD(iface, struct dom_parser, IDOMParser_iface); +} + +DISPEX_IDISPATCH_IMPL(dom_parser, IDOMParser, impl_from_IDOMParser(iface)->dispex) + +static HRESULT WINAPI dom_parser_parseFromString(IDOMParser *iface, BSTR string, BSTR mimeType, IHTMLDocument2 **ppNode) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); + + return E_NOTIMPL; +} + +static const IDOMParserVtbl dom_parser_vtbl = { + dom_parser_QueryInterface, + dom_parser_AddRef, + dom_parser_Release, + dom_parser_GetTypeInfoCount, + dom_parser_GetTypeInfo, + dom_parser_GetIDsOfNames, + dom_parser_Invoke, + dom_parser_parseFromString +}; + +static inline struct dom_parser *dom_parser_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct dom_parser, dispex); +} + +static void *dom_parser_query_interface(DispatchEx *dispex, REFIID riid) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + + if(IsEqualGUID(&IID_IDOMParser, riid)) + return &This->IDOMParser_iface; + + return NULL; +} + +static void dom_parser_destructor(DispatchEx *dispex) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + free(This); +} + +static HRESULT init_dom_parser_ctor(struct constructor*); + +static const dispex_static_data_vtbl_t dom_parser_dispex_vtbl = { + .query_interface = dom_parser_query_interface, + .destructor = dom_parser_destructor, +}; + +static const tid_t dom_parser_iface_tids[] = { + IDOMParser_tid, + 0 +}; + +dispex_static_data_t DOMParser_dispex = { + .id = OBJID_DOMParser, + .init_constructor = &init_dom_parser_ctor, + .vtbl = &dom_parser_dispex_vtbl, + .disp_tid = DispDOMParser_tid, + .iface_tids = dom_parser_iface_tids, +}; + +static HRESULT dom_parser_ctor_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + struct constructor *This = constructor_from_DispatchEx(dispex); + struct dom_parser *ret; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + break; + default: + FIXME("flags %x not supported\n", flags); + return E_NOTIMPL; + } + + if(!(ret = calloc(1, sizeof(*ret)))) + return E_OUTOFMEMORY; + + ret->IDOMParser_iface.lpVtbl = &dom_parser_vtbl; + init_dispatch(&ret->dispex, &DOMParser_dispex, This->window, dispex_compat_mode(&This->dispex)); + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)&ret->IDOMParser_iface; + return S_OK; +} + +static const dispex_static_data_vtbl_t dom_parser_ctor_dispex_vtbl = { + .destructor = constructor_destructor, + .traverse = constructor_traverse, + .unlink = constructor_unlink, + .value = dom_parser_ctor_value, +}; + +static dispex_static_data_t dom_parser_ctor_dispex = { + .name = "DOMParser", + .constructor_id = OBJID_DOMParser, + .vtbl = &dom_parser_ctor_dispex_vtbl, +}; + +static HRESULT init_dom_parser_ctor(struct constructor *constr) +{ + init_dispatch(&constr->dispex, &dom_parser_ctor_dispex, constr->window, + dispex_compat_mode(&constr->window->event_target.dispex)); + return S_OK; +} + typedef struct { DispatchEx dispex; IHTMLScreen IHTMLScreen_iface; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index d671f43a1f5..cd18193bd1c 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -333,6 +333,7 @@ sync_test("builtin_toString", function() { if(v >= 9) { test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); test("doctype", document.doctype, "DocumentType"); + test("domParser", new DOMParser(), "DOMParser");
test("Event", document.createEvent("Event"), "Event"); test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent"); @@ -980,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("DOMParser", v >= 9); test_exposed("MutationObserver", v >= 11); test_exposed("PageTransitionEvent", v >= 11); test_exposed("ProgressEvent", v >= 10); @@ -1202,6 +1204,7 @@ sync_test("constructor props", function() { test_exposed(Image, "create", v < 9); test_exposed(Option, "create", v < 9); test_exposed(XMLHttpRequest, "create", true); + if(v >= 9) test_exposed(DOMParser, "create", false); if(v >= 11) test_exposed(MutationObserver, "create", false); });
@@ -3878,6 +3881,9 @@ sync_test("prototypes", function() { check(document.createElement("option"), HTMLOptionElement.prototype, "option elem"); check(HTMLOptionElement.prototype, HTMLElement.prototype, "option elem prototype"); check(Option, Function.prototype, "Option constructor"); + check(new DOMParser(), DOMParser.prototype, "dom parser"); + check(DOMParser.prototype, Object.prototype, "dom parser prototype"); + check(DOMParser, Function.prototype, "dom parser constructor"); if(v >= 11) { check(new MutationObserver(function() {}), MutationObserver.prototype, "mutation observer"); check(MutationObserver.prototype, Object.prototype, "mutation observer prototype"); @@ -4181,6 +4187,7 @@ sync_test("prototype props", function() { ]); check(DocumentFragment, [ ["attachEvent",9,10], ["detachEvent",9,10], "querySelector", "querySelectorAll", "removeNode", "replaceNode", "swapNode" ]); check(DocumentType, [ "entities", "internalSubset", "name", "notations", "publicId", "systemId" ]); + check(DOMParser, [ "parseFromString" ]); check(Element, [ "childElementCount", "clientHeight", "clientLeft", "clientTop", "clientWidth", ["fireEvent",9,10], "firstElementChild", "getAttribute", "getAttributeNS", "getAttributeNode", "getAttributeNodeNS", "getBoundingClientRect", "getClientRects", @@ -4412,7 +4419,7 @@ sync_test("constructors", function() { if(v < 9) return;
- var ctors = [ "Image", "Option", "XMLHttpRequest" ]; + var ctors = [ "DOMParser", "Image", "Option", "XMLHttpRequest" ]; if (v >= 11) ctors.push("MutationObserver"); for(i = 0; i < ctors.length; i++) { @@ -4544,7 +4551,7 @@ async_test("window own props", function() { "BeforeUnloadEvent", ["Blob",10], "BookmarkCollection", "CanvasGradient", "CanvasPattern", "CanvasPixelArray", "CanvasRenderingContext2D", "CDATASection", ["CloseEvent",10], "CompositionEvent", "ControlRangeCollection", "Coordinates", ["Crypto",11], ["CryptoOperation",11], "CSSFontFaceRule", "CSSImportRule", ["CSSKeyframeRule",10], ["CSSKeyframesRule",10], "CSSMediaRule", "CSSNamespaceRule", "CSSPageRule", "CSSRuleList", "DataTransfer", ["DataView",9,9], "Debug", ["DeviceAcceleration",11], ["DeviceMotionEvent",11], - ["DeviceOrientationEvent",11], ["DeviceRotationRate",11], ["DOMError",10], "DOMException", "DOMParser", ["DOMSettableTokenList",10], ["DOMStringList",10], ["DOMStringMap",11], + ["DeviceOrientationEvent",11], ["DeviceRotationRate",11], ["DOMError",10], "DOMException", ["DOMSettableTokenList",10], ["DOMStringList",10], ["DOMStringMap",11], "DragEvent", ["ErrorEvent",10], "EventException", ["EXT_texture_filter_anisotropic",11], ["File",10], ["FileList",10], ["FileReader",10], ["Float32Array",10], ["Float64Array",10], "FocusEvent", ["FormData",10], "Geolocation", "GetObject", ["HTMLAllCollection",11], "HTMLAppletElement", "HTMLAreasCollection", "HTMLAudioElement", "HTMLBaseElement", "HTMLBaseFontElement", "HTMLBGSoundElement", "HTMLBlockElement", "HTMLBRElement", "HTMLCanvasElement", ["HTMLDataListElement",10], "HTMLDDElement", "HTMLDirectoryElement", diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 1781df69ee3..67f974bbacf 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2814,6 +2814,17 @@ sync_test("screen", function() { ok(!check_enum(o, "prop2"), "prop2 enumerated"); });
+sync_test("DOMParser", function() { + var p, r = DOMParser.length; + ok(r === 0, "length = " + r); + + p = DOMParser(); + r = Object.getPrototypeOf(p); + ok(r === DOMParser.prototype, "prototype of instance created without new = " + r); + ok(p !== new DOMParser(), "DOMParser() == new DOMParser()"); + ok(new DOMParser() !== new DOMParser(), "new DOMParser() == new DOMParser()"); +}); + sync_test("builtin_func", function() { var o = document.implementation, r; var f = o.hasFeature;
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 | 17 +++++++++++++++-- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 6 +++++- dlls/mshtml/tests/xhr.js | 22 ++++++++++++++++++++++ dlls/mshtml/tests/xmlhttprequest.c | 15 +++++++++++++++ dlls/mshtml/xmlhttprequest.c | 14 ++++++++++++++ 6 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 7255e8d9ec3..cbb668ad81f 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5634,7 +5634,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 : This->html_document ? &HTMLDocument_dispex : &XMLDocument_dispex; return This->script_global; }
@@ -5870,6 +5870,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; @@ -5921,6 +5932,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) { + dispex_static_data_t *dispex = &XMLDocument_dispex; HTMLDocumentObj *doc_obj = browser->doc; HTMLDocumentNode *doc;
@@ -5941,12 +5953,13 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI if(NS_SUCCEEDED(nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMHTMLDocument, (void**)&doc->html_document))) { doc->dom_document = (nsIDOMDocument*)doc->html_document; nsIDOMHTMLDocument_Release(doc->html_document); + dispex = &HTMLDocument_dispex; }else { doc->dom_document = nsdoc; 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);
init_document_mutation(doc); doc_init_events(doc); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 50f147531d1..c561517eaf2 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 { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index cd18193bd1c..3688cc5f619 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() { @@ -4587,7 +4591,7 @@ async_test("window own props", function() { ["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" + ["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..61561d3a2b7 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, + 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);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 47 ++++++++++++++++++++++++------------ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/xhr.js | 11 +++++++-- 3 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index cbb668ad81f..821edb40a26 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -1265,10 +1265,10 @@ static HRESULT WINAPI HTMLDocument_get_defaultCharset(IHTMLDocument2 *iface, BST static HRESULT WINAPI HTMLDocument_get_mimeType(IHTMLDocument2 *iface, BSTR *p) { HTMLDocumentNode *This = impl_from_IHTMLDocument2(iface); - const PRUnichar *content_type; + const WCHAR *content_type; + const PRUnichar *str; nsAString nsstr; nsresult nsres; - HRESULT hres;
TRACE("(%p)->(%p)\n", This, p);
@@ -1277,15 +1277,21 @@ static HRESULT WINAPI HTMLDocument_get_mimeType(IHTMLDocument2 *iface, BSTR *p) if(This->window && !This->window->navigation_start_time) return (*p = SysAllocString(L"")) ? S_OK : E_FAIL;
- nsAString_InitDepend(&nsstr, NULL); - nsres = nsIDOMDocument_GetContentType(This->dom_document, &nsstr); - if(NS_FAILED(nsres)) - return map_nsresult(nsres); + if(This->is_xhtml) + content_type = L"application/xhtml+xml"; + else if(This->html_document) + content_type = L"text/html"; + else { + nsAString_Init(&nsstr, NULL); + nsres = nsIDOMDocument_GetContentType(This->dom_document, &nsstr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres);
- nsAString_GetData(&nsstr, &content_type); - hres = get_mime_type_display_name(content_type, p); - nsAString_Finish(&nsstr); - return hres; + nsAString_GetData(&nsstr, &str); + content_type = !wcscmp(str, L"image/svg+xml") ? L"image/svg+xml" : L"text/xml"; + nsAString_Finish(&nsstr); + } + return get_mime_type_display_name(content_type, p); }
static HRESULT WINAPI HTMLDocument_get_fileSize(IHTMLDocument2 *iface, BSTR *p) @@ -5935,11 +5941,23 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI dispex_static_data_t *dispex = &XMLDocument_dispex; HTMLDocumentObj *doc_obj = browser->doc; HTMLDocumentNode *doc; + const PRUnichar *str; + nsAString nsstr; + nsresult nsres;
doc = alloc_doc_node(doc_obj, window, script_global); if(!doc) return E_OUTOFMEMORY;
+ nsAString_Init(&nsstr, NULL); + nsres = nsIDOMDocument_GetContentType(nsdoc, &nsstr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + nsAString_GetData(&nsstr, &str); + if(!wcscmp(str, L"application/xhtml+xml")) + doc->is_xhtml = TRUE; + nsAString_Finish(&nsstr); + if(parent_mode >= COMPAT_MODE_IE9) { TRACE("using parent mode %u\n", parent_mode); doc->document_mode = parent_mode; @@ -5970,12 +5988,9 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc->browser = browser;
if(browser->usermode == EDITMODE && doc->html_document) { - nsAString mode_str; - nsresult nsres; - - nsAString_InitDepend(&mode_str, L"on"); - nsres = nsIDOMHTMLDocument_SetDesignMode(doc->html_document, &mode_str); - nsAString_Finish(&mode_str); + nsAString_InitDepend(&nsstr, L"on"); + nsres = nsIDOMHTMLDocument_SetDesignMode(doc->html_document, &nsstr); + nsAString_Finish(&nsstr); if(NS_FAILED(nsres)) ERR("SetDesignMode failed: %08lx\n", nsres); } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index c561517eaf2..89276ffa22f 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1149,6 +1149,7 @@ struct HTMLDocumentNode { unsigned int emulate_mode : 1; unsigned int content_ready : 1; unsigned int unload_sent : 1; + unsigned int is_xhtml : 1;
IHTMLDOMImplementation *dom_implementation; IHTMLNamespaceCollection *namespaces; diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 46aed46624c..7c553dc25ea 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -259,9 +259,16 @@ async_test("content_types", function() {
function onload() { ok(xhr.responseText === xml, "unexpected responseText " + xhr.responseText); - if(v < 10 || types === xml_types) + if(v < 10 || types === xml_types) { ok(xhr.responseXML !== null, "unexpected null responseXML for " + types[i]); - else + if(v >= 10) { + var r = xhr.responseXML.mimeType, e = "text/xml"; + if(types[i] === "application/xHtml+xml" || types[i] === "image/SvG+xml") + e = types[i].toLowerCase(); + e = external.getExpectedMimeType(e); + ok(r === e, "XML document mimeType for " + types[i] + " = " + r + ", expected " + e); + } + }else ok(xhr.responseXML === null, "unexpected non-null responseXML for " + (override ? "overridden " : "") + types[i]);
if(("overrideMimeType" in xhr) && !override) {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 21 ++++++++++----------- dlls/mshtml/tests/xhr.js | 2 ++ 2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 821edb40a26..b1286d1c19c 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -613,21 +613,20 @@ static HRESULT WINAPI HTMLDocument_get_anchors(IHTMLDocument2 *iface, IHTMLEleme return E_UNEXPECTED; }
- if(!This->html_document) { - FIXME("Not implemented for XML document\n"); - return E_NOTIMPL; - } + if(This->is_xhtml) + FIXME("Not implemented for XHTML Document, returning empty list\n");
- nsres = nsIDOMHTMLDocument_GetAnchors(This->html_document, &nscoll); - if(NS_FAILED(nsres)) { - ERR("GetAnchors failed: %08lx\n", nsres); - return E_FAIL; + if(This->html_document) { + nsres = nsIDOMHTMLDocument_GetAnchors(This->html_document, &nscoll); + if(NS_FAILED(nsres)) { + ERR("GetAnchors failed: %08lx\n", nsres); + return E_FAIL; + } }
- if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, &This->node.event_target.dispex); + *p = create_collection_from_htmlcol(nscoll, &This->node.event_target.dispex); + if(nscoll) nsIDOMHTMLCollection_Release(nscoll); - }
return S_OK; } diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 7c553dc25ea..7685a5a8486 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -49,6 +49,8 @@ async_test("async_xhr", function() { }else { ok("anchors" in x, "anchors not in returned XML document"); ok(!x.hasOwnProperty("createElement"), "createElement is a prop of returned XML document"); + r = x.anchors; + ok(r.length === 0, "anchors.length of returned XML document = " + r.length); }
if(complete_cnt++ && !("onloadend" in xhr))
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/nsembed.c | 43 ++++++++++++++ dlls/mshtml/nsiface.idl | 13 +++++ dlls/mshtml/omnavigator.c | 82 +++++++++++++++++++++++++- dlls/mshtml/tests/documentmode.js | 3 + dlls/mshtml/tests/es5.js | 96 ++++++++++++++++++++++++++++++- 6 files changed, 236 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 89276ffa22f..99fceca350b 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -76,6 +76,7 @@ #define MSHTML_E_INVALID_PROPERTY 0x800a01b6 #define MSHTML_E_INVALID_ACTION 0x800a01bd #define MSHTML_E_NODOC 0x800a025c +#define MSHTML_E_SYNTAX 0x800a03ea #define MSHTML_E_NOT_FUNC 0x800a138a
typedef struct HTMLWindow HTMLWindow; @@ -1285,6 +1286,7 @@ HRESULT nsnode_to_nsstring(nsIDOMNode*,nsAString*); void setup_editor_controller(GeckoBrowser*); nsresult get_nsinterface(nsISupports*,REFIID,void**); nsIWritableVariant *create_nsvariant(void); +nsIDOMParser *create_nsdomparser(HTMLDocumentNode*); nsIXMLHttpRequest *create_nsxhr(nsIDOMWindow *nswindow); nsresult create_nsfile(const PRUnichar*,nsIFile**); char *get_nscategory_entry(const char*,const char*); diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index 5480c4ed044..cbaf05e6345 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -42,6 +42,7 @@ WINE_DECLARE_DEBUG_CHANNEL(gecko); #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1" #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1" #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html" +#define NS_DOMPARSER_CONTRACTID "@mozilla.org/xmlextras/domparser;1" #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1" #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1" #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" @@ -2415,6 +2416,48 @@ __ASM_GLOBAL_FUNC(call_thiscall_func, #define nsIScriptObjectPrincipal_GetPrincipal(this) ((void* (WINAPI*)(void*,void*))&call_thiscall_func)((this)->lpVtbl->GetPrincipal,this) #endif
+nsIDOMParser *create_nsdomparser(HTMLDocumentNode *doc_node) +{ + nsIScriptObjectPrincipal *sop; + mozIDOMWindow *inner_window; + nsIGlobalObject *nsglo; + nsIDOMParser *nsparser; + nsIPrincipal *nspri; + nsresult nsres; + + nsres = nsIDOMWindow_GetInnerWindow(doc_node->window->dom_window, &inner_window); + if(NS_FAILED(nsres)) { + ERR("Could not get inner window: %08lx\n", nsres); + return NULL; + } + + nsres = mozIDOMWindow_QueryInterface(inner_window, &IID_nsIGlobalObject, (void**)&nsglo); + mozIDOMWindow_Release(inner_window); + assert(nsres == NS_OK); + + nsres = nsIGlobalObject_QueryInterface(nsglo, &IID_nsIScriptObjectPrincipal, (void**)&sop); + assert(nsres == NS_OK); + + /* The returned principal is *not* AddRef'd */ + nspri = nsIScriptObjectPrincipal_GetPrincipal(sop); + nsIScriptObjectPrincipal_Release(sop); + + nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, + NS_DOMPARSER_CONTRACTID, NULL, &IID_nsIDOMParser, (void**)&nsparser); + if(NS_SUCCEEDED(nsres)) { + nsres = nsIDOMParser_Init(nsparser, nspri, NULL, NULL, nsglo); + if(NS_FAILED(nsres)) + nsIDOMParser_Release(nsparser); + } + nsIGlobalObject_Release(nsglo); + if(NS_FAILED(nsres)) { + ERR("nsIDOMParser_Init failed: %08lx\n", nsres); + return NULL; + } + + return nsparser; +} + nsIXMLHttpRequest *create_nsxhr(nsIDOMWindow *nswindow) { nsIScriptObjectPrincipal *sop; diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl index 43786b490f5..1f2131dfb24 100644 --- a/dlls/mshtml/nsiface.idl +++ b/dlls/mshtml/nsiface.idl @@ -4369,6 +4369,19 @@ interface nsIScriptObjectPrincipal : nsISupports nsIPrincipal* /* thiscall */ GetPrincipal(); }
+[ + object, + uuid(70b9600e-8622-4c93-9ad8-22c28058dc44), + local +] +interface nsIDOMParser : nsISupports +{ + nsresult ParseFromString(const char16_t *str, const char *contentType, nsIDOMDocument **_retval); + nsresult ParseFromBuffer(const uint8_t *buf, uint32_t bufLen, const char *aContentType, nsIDOMDocument **_retval); + nsresult ParseFromStream(nsIInputStream *stream, const char *charset, int32_t contentLength, const char *contentType, nsIDOMDocument **_retval); + nsresult Init(nsIPrincipal *principal, nsIURI *documentURI, nsIURI *baseURI, nsIGlobalObject *scriptObject); +} + [ object, uuid(6f54214c-7175-498d-9d2d-0429e38c2869), diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index c65fb675372..3608dec8586 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -272,6 +272,8 @@ void detach_dom_implementation(IHTMLDOMImplementation *iface) struct dom_parser { DispatchEx dispex; IDOMParser IDOMParser_iface; + + HTMLDocumentNode *doc; };
static inline struct dom_parser *impl_from_IDOMParser(IDOMParser *iface) @@ -283,11 +285,65 @@ DISPEX_IDISPATCH_IMPL(dom_parser, IDOMParser, impl_from_IDOMParser(iface)->dispe
static HRESULT WINAPI dom_parser_parseFromString(IDOMParser *iface, BSTR string, BSTR mimeType, IHTMLDocument2 **ppNode) { + char content_type[sizeof("application/xhtml+xml") /* longest supported */]; struct dom_parser *This = impl_from_IDOMParser(iface); + nsIDOMDocument *nsdoc = NULL; + nsAString errns, errtag; + HTMLDocumentNode *doc; + nsIDOMNodeList *nodes; + nsIDOMParser *parser; + nsresult nsres; + HRESULT hres; + unsigned i;
- FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); + TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode);
- return E_NOTIMPL; + if(!string || !mimeType) + return E_INVALIDARG; + + for(i = 0; i < ARRAY_SIZE(content_type); i++) { + if(mimeType[i] > 'z') + return E_INVALIDARG; + content_type[i] = tolower(mimeType[i]); + if(!mimeType[i]) + break; + } + if(i >= ARRAY_SIZE(content_type)) + return E_INVALIDARG; + + if(!(parser = create_nsdomparser(This->doc))) + return E_FAIL; + nsres = nsIDOMParser_ParseFromString(parser, string ? string : L"", content_type, &nsdoc); + nsIDOMParser_Release(parser); + if(NS_FAILED(nsres)) + return (nsres == NS_ERROR_NOT_IMPLEMENTED) ? E_INVALIDARG : map_nsresult(nsres); + + if(strcmp(content_type, "text/html")) { + nsAString_InitDepend(&errns, L"http://www.mozilla.org/newlayout/xml/parsererror.xml"); + nsAString_InitDepend(&errtag, L"parsererror"); + nsres = nsIDOMDocument_GetElementsByTagNameNS(nsdoc, &errns, &errtag, &nodes); + nsAString_Finish(&errtag); + nsAString_Finish(&errns); + if(NS_SUCCEEDED(nsres)) { + UINT32 length; + nsres = nsIDOMNodeList_GetLength(nodes, &length); + nsIDOMNodeList_Release(nodes); + if(NS_SUCCEEDED(nsres) && length) { + nsIDOMDocument_Release(nsdoc); + return MSHTML_E_SYNTAX; + } + } + } + + hres = create_document_node(nsdoc, This->doc->browser, NULL, This->doc->script_global, This->doc->document_mode, &doc); + nsIDOMDocument_Release(nsdoc); + if(FAILED(hres)) + return hres; + + /* make sure dispex info is initialized */ + dispex_compat_mode(&doc->node.event_target.dispex); + *ppNode = &doc->IHTMLDocument2_iface; + return hres; }
static const IDOMParserVtbl dom_parser_vtbl = { @@ -316,6 +372,23 @@ static void *dom_parser_query_interface(DispatchEx *dispex, REFIID riid) return NULL; }
+static void dom_parser_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + if(This->doc) + note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb); +} + +static void dom_parser_unlink(DispatchEx *dispex) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + if(This->doc) { + HTMLDocumentNode *doc = This->doc; + This->doc = NULL; + IHTMLDOMNode_Release(&doc->node.IHTMLDOMNode_iface); + } +} + static void dom_parser_destructor(DispatchEx *dispex) { struct dom_parser *This = dom_parser_from_DispatchEx(dispex); @@ -327,6 +400,8 @@ static HRESULT init_dom_parser_ctor(struct constructor*); static const dispex_static_data_vtbl_t dom_parser_dispex_vtbl = { .query_interface = dom_parser_query_interface, .destructor = dom_parser_destructor, + .traverse = dom_parser_traverse, + .unlink = dom_parser_unlink };
static const tid_t dom_parser_iface_tids[] = { @@ -367,6 +442,9 @@ static HRESULT dom_parser_ctor_value(DispatchEx *dispex, LCID lcid, WORD flags, return E_OUTOFMEMORY;
ret->IDOMParser_iface.lpVtbl = &dom_parser_vtbl; + ret->doc = This->window->doc; + IHTMLDOMNode_AddRef(&ret->doc->node.IHTMLDOMNode_iface); + init_dispatch(&ret->dispex, &DOMParser_dispex, This->window, dispex_compat_mode(&This->dispex));
V_VT(res) = VT_DISPATCH; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3688cc5f619..6a90f9f7a8b 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -334,6 +334,9 @@ sync_test("builtin_toString", function() { test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); test("doctype", document.doctype, "DocumentType"); test("domParser", new DOMParser(), "DOMParser"); + test("svgDocument", new DOMParser().parseFromString("<tag>foobar</tag>", "image/svg+xml"), v < 11 ? "Document" : "XMLDocument"); + test("xhtmlDocument", new DOMParser().parseFromString("<tag>foobar</tag>", "application/xhtml+xml"), v < 11 ? "Document" : "XMLDocument"); + test("xmlDocument", new DOMParser().parseFromString("<tag>foobar</tag>", "text/xml"), v < 11 ? "Document" : "XMLDocument");
test("Event", document.createEvent("Event"), "Event"); test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 67f974bbacf..02f72586d26 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2815,7 +2815,7 @@ sync_test("screen", function() { });
sync_test("DOMParser", function() { - var p, r = DOMParser.length; + var p, r = DOMParser.length, mimeType; ok(r === 0, "length = " + r);
p = DOMParser(); @@ -2823,6 +2823,100 @@ sync_test("DOMParser", function() { ok(r === DOMParser.prototype, "prototype of instance created without new = " + r); ok(p !== new DOMParser(), "DOMParser() == new DOMParser()"); ok(new DOMParser() !== new DOMParser(), "new DOMParser() == new DOMParser()"); + + var teststr = { toString: function() { return "<a name="test">wine</a>"; } }; + + // HTML mime types + mimeType = [ + "text/hTml" + ]; + for(var i = 0; i < mimeType.length; i++) { + var m = mimeType[i], html = p.parseFromString(teststr, m), e = external.getExpectedMimeType(m.toLowerCase()); + r = html.mimeType; + ok(r === e, "mimeType of HTML document with mime type " + m + " = " + r + ", expected " + e); + r = html.childNodes; + ok(r.length === 1 || r.length === 2, "childNodes.length of HTML document with mime type " + m + " = " + r.length); + var html_elem = r[r.length - 1]; + ok(html_elem.nodeName === "HTML", "child nodeName of HTML document with mime type " + m + " = " + html_elem.nodeName); + ok(html_elem.nodeValue === null, "child nodeValue of HTML document with mime type " + m + " = " + html_elem.nodeValue); + r = html.anchors; + ok(r.length === 1, "anchors.length of HTML document with mime type " + m + " = " + r.length); + r = r[0]; + ok(r.nodeName === "A", "anchor nodeName of HTML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "anchor nodeValue of HTML document with mime type " + m + " = " + r.nodeValue); + r = r.parentNode; + ok(r.nodeName === "BODY", "anchor parent nodeName of HTML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "anchor parent nodeValue of HTML document with mime type " + m + " = " + r.nodeValue); + r = r.parentNode; + ok(r === html_elem, "body parent of HTML document with mime type " + m + " = " + r); + } + + // XML mime types + mimeType = [ + "text/xmL", + "aPPlication/xml", + "application/xhtml+xml", + "image/svg+xml" + ]; + for(var i = 0; i < mimeType.length; i++) { + var m = mimeType[i], xml = p.parseFromString(teststr, m), e; + e = external.getExpectedMimeType(m === "aPPlication/xml" ? "text/xml" : m.toLowerCase()); + r = xml.mimeType; + ok(r === e, "mimeType of XML document with mime type " + m + " = " + r + ", expected " + e); + r = xml.childNodes; + ok(r.length === 1, "childNodes.length of XML document with mime type " + m + " = " + r.length); + r = r[0]; + ok(r.nodeName === "a", "child nodeName of XML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "child nodeValue of XML document with mime type " + m + " = " + r.nodeValue); + r = r.childNodes; + ok(r.length === 1, "childNodes of child.length of XML document with mime type " + m + " = " + r.length); + r = r[0]; + ok(r.nodeName === "#text", "child of child nodeName of XML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === "wine", "child of child nodeValue of XML document with mime type " + m + " = " + r.nodeValue); + ok(!("test" in xml), "'test' in XML document with mime type " + m); + + // test HTMLDocument specific props, which are available in DocumentPrototype, + // so they are shared in XMLDocument since they both have the same prototype + r = xml.anchors; + if(m === "application/xhtml+xml") { + todo_wine. + ok(r.length === 1, "anchors.length of XML document with mime type " + m + " = " + r.length); + r = r[0]; + todo_wine. + ok(r === xml.childNodes[0], "anchor of XML document with mime type " + m + " = " + r); + }else { + ok(r.length === 0, "anchors.length of XML document with mime type " + m + " = " + r.length); + } + } + + // Invalid mime types + mimeType = [ + "application/html", + "wine/test+xml", + "image/jpeg", + "text/plain", + "html", + "+xml", + "xml", + 42 + ]; + for(var i = 0; i < mimeType.length; i++) { + try { + p.parseFromString(teststr, mimeType[i]); + ok(false, "expected exception calling parseFromString with mime type " + mimeType[i]); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === E_INVALIDARG, "parseFromString with mime type " + mimeType[i] + " threw " + n); + } + } + + try { + r = p.parseFromString("<invalid>xml", "text/xml"); + ok(false, "expected exception calling parseFromString with invalid xml"); + }catch(ex) { + ok(ex.name === "SyntaxError", "parseFromString with invalid xml threw " + ex.name); + } + p.parseFromString("<parsererror></parsererror>", "text/xml"); });
sync_test("builtin_func", function() {
Jacek Caban (@jacek) commented about dlls/mshtml/xmlhttprequest.c:
*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,
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);
We have the same in `DOMImplementation`. We could move it to `create_document_node` when NULL window is passed, we always want it in such cases.
Jacek Caban (@jacek) commented about dlls/mshtml/htmldoc.c:
const PRUnichar *str;
nsAString nsstr;
nsresult nsres;
doc = alloc_doc_node(doc_obj, window, script_global); if(!doc) return E_OUTOFMEMORY;
nsAString_Init(&nsstr, NULL);
nsres = nsIDOMDocument_GetContentType(nsdoc, &nsstr);
if(NS_FAILED(nsres))
return map_nsresult(nsres);
nsAString_GetData(&nsstr, &str);
if(!wcscmp(str, L"application/xhtml+xml"))
doc->is_xhtml = TRUE;
nsAString_Finish(&nsstr);
Earlier I thought Gecko exposed `nsIDOMHTMLDocument` for XHTML. If it doesn’t, then the current `html_document` check should cover most cases. Why don’t we just skip the flag for now and do the fixup in `get_mimeType`? It seems to me we could always query the content type there, and use "text/xml" if it isn’t one of the known ones.
Jacek Caban (@jacek) commented about dlls/mshtml/htmldoc.c:
return E_UNEXPECTED; }
- if(!This->html_document) {
FIXME("Not implemented for XML document\n");
return E_NOTIMPL;
- }
- if(This->is_xhtml)
FIXME("Not implemented for XHTML Document, returning empty list\n");
SVG documents may also have anchors. I don’t mean to suggest digging deeper, but we could just adjust the FIXME and print it for all non-HTML documents.
Jacek Caban (@jacek) commented about dlls/mshtml/omnavigator.c:
return (nsres == NS_ERROR_NOT_IMPLEMENTED) ? E_INVALIDARG : map_nsresult(nsres);
- if(strcmp(content_type, "text/html")) {
nsAString_InitDepend(&errns, L"http://www.mozilla.org/newlayout/xml/parsererror.xml");
nsAString_InitDepend(&errtag, L"parsererror");
nsres = nsIDOMDocument_GetElementsByTagNameNS(nsdoc, &errns, &errtag, &nodes);
nsAString_Finish(&errtag);
nsAString_Finish(&errns);
if(NS_SUCCEEDED(nsres)) {
UINT32 length;
nsres = nsIDOMNodeList_GetLength(nodes, &length);
nsIDOMNodeList_Release(nodes);
if(NS_SUCCEEDED(nsres) && length) {
nsIDOMDocument_Release(nsdoc);
return MSHTML_E_SYNTAX;
}
Some debug trace of this happening would be nice.
Jacek Caban (@jacek) commented about dlls/mshtml/omnavigator.c:
struct dom_parser { DispatchEx dispex; IDOMParser IDOMParser_iface;
- HTMLDocumentNode *doc;
You could use `get_script_global(&This->dispex)` to avoid storing document here. This works only for IE9+ modes, but that's fine here.
On Wed Aug 27 21:30:27 2025 +0000, Jacek Caban wrote:
Earlier I thought Gecko exposed `nsIDOMHTMLDocument` for XHTML. If it doesn’t, then the current `html_document` check should cover most cases. Why don’t we just skip the flag for now and do the fixup in `get_mimeType`? It seems to me we could always query the content type there, and use "text/xml" if it isn’t one of the known ones.
On second thought the change to `get_mimeType` probably isn't quite correct. Upon closer look it seems IE may have "image" documents for example, it's probably something specific to XHR (or rather responseXML), I'll do more testing.