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() {