Skip to content

Expose a method to obtain the parser from the document.

Gabriel Ivăncescu requested to merge insn/wine-gecko:parser into master

We'll need this to use the parser to set the default charset for pages that don't have any specified. This is because native uses the system codepage in such cases, whereas Gecko seems to always use windows-1252. This breaks some apps that rely on a hardcoded system codepage and don't have charset specified on their web pages. (and yes, I know they are broken…)

Here's a way to test it. Patch to Wine:

 dlls/mshtml/main.c           | 16 ++++++++++++++
 dlls/mshtml/mshtml_private.h |  2 ++
 dlls/mshtml/mutation.c       | 41 +++++++++++++++++++++++++++++++++---
 dlls/mshtml/nsiface.idl      |  2 ++
 4 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/dlls/mshtml/main.c b/dlls/mshtml/main.c
index a45a2c1..e8f48bb 100644
--- a/dlls/mshtml/main.c
+++ b/dlls/mshtml/main.c
@@ -126,6 +126,22 @@ BSTR charset_string_from_cp(UINT cp)
     return SysAllocString(info.wszWebCharset);
 }
 
+void set_default_charset_from_cp(nsIParser *parser, UINT cp)
+{
+    nsACString charset_str;
+    MIMECPINFO info;
+    char charset[ARRAY_SIZE(info.wszWebCharset) * 3];
+
+    if(!ensure_mlang() || FAILED(IMultiLanguage2_GetCodePageInfo(mlang, cp, GetUserDefaultUILanguage(), &info)))
+        return;
+
+    WideCharToMultiByte(CP_ACP, 0, info.wszWebCharset, -1, charset, sizeof(charset), NULL, NULL);
+
+    nsACString_InitDepend(&charset_str, charset);
+    nsIParser_SetDocumentCharset(parser, &charset_str, 0);
+    nsACString_Finish(&charset_str);
+}
+
 HRESULT get_mime_type_display_name(const WCHAR *content_type, BSTR *ret)
 {
     /* undocumented */
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 9609fb5..98d465b 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -952,6 +952,7 @@ struct HTMLDocumentNode {
 
     nsIDOMDocument *dom_document;
     nsIDOMHTMLDocument *html_document;
+    unsigned int skip_default_charset : 1;
     unsigned int content_ready : 1;
     unsigned int unload_sent : 1;
 
@@ -1492,6 +1493,7 @@ extern void *call_thiscall_func;
 compat_mode_t get_max_compat_mode(IUri*);
 UINT cp_from_charset_string(BSTR);
 BSTR charset_string_from_cp(UINT);
+void set_default_charset_from_cp(nsIParser*,UINT);
 HRESULT get_mime_type_display_name(const WCHAR*,BSTR*);
 HINSTANCE get_shdoclc(void);
 void set_statustext(HTMLDocumentObj*,INT,LPCWSTR);
diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c
index 845c189..0144d9b 100644
--- a/dlls/mshtml/mutation.c
+++ b/dlls/mshtml/mutation.c
@@ -552,10 +552,17 @@ void process_document_response_headers(HTMLDocumentNode *doc, IBinding *binding)
     IWinInetHttpInfo_Release(http_info);
 }
 
-static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element)
+static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element, nsIDOMElement *nselem)
 {
-    nsAString http_equiv_str, content_str;
+    nsAString http_equiv_str, content_str, charset_str;
     nsresult nsres;
+    cpp_bool b;
+
+    nsAString_InitDepend(&charset_str, L"charset");
+    nsres = nsIDOMElement_HasAttribute(nselem, &charset_str, &b);
+    if(NS_SUCCEEDED(nsres) && b)
+        doc->skip_default_charset = TRUE;
+    nsAString_Finish(&charset_str);
 
     nsAString_Init(&http_equiv_str, NULL);
     nsAString_Init(&content_str, NULL);
@@ -577,6 +584,13 @@ static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *m
                 set_document_mode(doc, document_mode, TRUE);
             else
                 FIXME("Unsupported document mode %s\n", debugstr_w(content));
+        }else if(!doc->skip_default_charset && !wcsicmp(http_equiv, L"content-type")) {
+            const WCHAR *p = wcschr(content, ';');
+            if(p) {
+                while(*(++p) && iswspace(*p)) { }
+                if(!wcsnicmp(p, L"charset=", 8))
+                    doc->skip_default_charset = TRUE;
+            }
         }
     }
 
@@ -864,6 +878,7 @@ static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface,
     nsIDOMHTMLFrameElement *nsframe;
     nsIDOMHTMLScriptElement *nsscript;
     nsIDOMHTMLMetaElement *nsmeta;
+    nsIDOMHTMLBodyElement *nsbody;
     nsIDOMElement *nselem;
     nsIDOMComment *nscomment;
     nsresult nsres;
@@ -948,9 +963,29 @@ static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface,
 
     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLMetaElement, (void**)&nsmeta);
     if(NS_SUCCEEDED(nsres)) {
-        process_meta_element(This, nsmeta);
+        process_meta_element(This, nsmeta, nselem);
         nsIDOMHTMLMetaElement_Release(nsmeta);
     }
+
+    if(!This->skip_default_charset) {
+        if(This->window->bscallback->nschannel->charset)
+            This->skip_default_charset = TRUE;
+        else {
+            nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLBodyElement, (void**)&nsbody);
+            if(NS_SUCCEEDED(nsres)) {
+                nsIParser *parser;
+
+                nsIDOMHTMLBodyElement_Release(nsbody);
+                This->skip_default_charset = TRUE;
+
+                nsres = nsIDOMDocument_GetParser(This->dom_document, &parser);
+                if(NS_SUCCEEDED(nsres) && parser) {
+                    set_default_charset_from_cp(parser, GetACP());
+                    nsIParser_Release(parser);
+                }
+            }
+        }
+    }
 }
 
 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl
index 43786b4..d1abf66 100644
--- a/dlls/mshtml/nsiface.idl
+++ b/dlls/mshtml/nsiface.idl
@@ -109,6 +109,7 @@ interface nsIDOMWindow;
 interface nsIDOMElement;
 interface nsIDOMRange;
 interface nsIDOMEventTarget;
+interface nsIParser;
 interface nsISelection;
 interface nsIDOMHTMLSelectElement;
 interface nsIFile;
@@ -1407,6 +1408,7 @@ interface nsIDOMDocument : nsIDOMNode
     nsresult GetCompatMode(nsAString *aCompatMode);
     nsresult QuerySelector(const nsAString *selectors, nsIDOMElement **_retval);
     nsresult QuerySelectorAll(const nsAString *selectors, nsIDOMNodeList **_retval);
+    nsresult GetParser(nsIParser **aParser);
 }
 
 [

And here's a hack to test it on Windows too:

diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c
index e6acf5a..8646c9b 100644
--- a/dlls/mshtml/tests/script.c
+++ b/dlls/mshtml/tests/script.c
@@ -5056,13 +5056,12 @@ static void run_script_as_http_with_mode(const char *script, const char *opt, co
 static void test_strict_mode(void)
 {
     sprintf(index_html_data,
-            "<!DOCTYPE html>\n"
             "<html>\n"
             "  <head>\n"
             "    <script src=\"winetest.js\" type=\"text/javascript\"></script>\n"
             "    <script type=\"text/javascript\">\n"
             "      function test() {\n"
-            "        ok(document.documentMode === 7, 'document mode = ' + document.documentMode);\n"
+            "        ok(false, 'charset: ' + document.charset + '  --  default: ' + document.defaultCharset);\n"
             "        next_test();\n"
             "      }\n"
             "      var tests = [ test ];\n"
@@ -5093,22 +5092,9 @@ static void init_protocol_handler(void)
 
 static void run_js_tests(void)
 {
-    run_js_script("jstest.html");
-    run_js_script("exectest.html");
-    run_js_script("events.html");
-
-    SET_EXPECT(GetTypeInfo);
-    run_js_script("vbtest.html");
-    CLEAR_CALLED(GetTypeInfo);
-
-    if(!is_ie9plus) {
-        win_skip("Skipping some script tests on IE older than 9.\n");
-        return;
-    }
-
     init_protocol_handler();
 
-    test_strict_mode();
+    test_strict_mode(); return;
     run_script_as_http_with_mode("xhr.js", NULL, "9");
     run_script_as_http_with_mode("xhr.js", NULL, "10");
     run_script_as_http_with_mode("xhr.js", NULL, "11");

Run mshtml_test script and observe the failure message.

The charset must match with the system codepage (the defaultCharset). Feel free to also add tags in the test to see that they should indeed override the default one (I had to parse them for charset).

Merge request reports

Loading