Jacek Caban : mshtml: Support registry configuration for maximal allowed compatibility mode.

Alexandre Julliard julliard at winehq.org
Tue Oct 9 16:22:47 CDT 2018


Module: wine
Branch: master
Commit: 5489529f4e20efeec908af38c2f0d1f2974aa59c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=5489529f4e20efeec908af38c2f0d1f2974aa59c

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Oct  9 12:22:16 2018 +0200

mshtml: Support registry configuration for maximal allowed compatibility mode.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/mshtml/main.c           | 125 +++++++++++++++++++++++++++++++++++++++++++
 dlls/mshtml/mshtml_private.h |   3 ++
 dlls/mshtml/mutation.c       |  60 +++++++++++++--------
 3 files changed, 166 insertions(+), 22 deletions(-)

diff --git a/dlls/mshtml/main.c b/dlls/mshtml/main.c
index 6ce8198..2ba648f 100644
--- a/dlls/mshtml/main.c
+++ b/dlls/mshtml/main.c
@@ -36,6 +36,7 @@
 #include "rpcproxy.h"
 #include "shlguid.h"
 #include "mlang.h"
+#include "wininet.h"
 
 #include "wine/debug.h"
 
@@ -53,6 +54,14 @@ DWORD mshtml_tls = TLS_OUT_OF_INDEXES;
 static HINSTANCE shdoclc = NULL;
 static WCHAR *status_strings[IDS_STATUS_LAST-IDS_STATUS_FIRST+1];
 static IMultiLanguage2 *mlang;
+static unsigned global_max_compat_mode = COMPAT_MODE_IE11;
+static struct list compat_config = LIST_INIT(compat_config);
+
+typedef struct {
+    struct list entry;
+    compat_mode_t max_compat_mode;
+    WCHAR host[1];
+} compat_config_t;
 
 static BOOL ensure_mlang(void)
 {
@@ -109,6 +118,114 @@ BSTR charset_string_from_cp(UINT cp)
     return SysAllocString(info.wszWebCharset);
 }
 
+static BOOL read_compat_mode(HKEY key, compat_mode_t *r)
+{
+    WCHAR version[32];
+    DWORD type, size;
+    LSTATUS status;
+
+    static const WCHAR max_compat_modeW[] = {'M','a','x','C','o','m','p','a','t','M','o','d','e',0};
+
+    size = sizeof(version);
+    status = RegQueryValueExW(key, max_compat_modeW, NULL, &type, (BYTE*)version, &size);
+    if(status != ERROR_SUCCESS || type != REG_SZ)
+        return FALSE;
+
+    return parse_compat_version(version, r);
+}
+
+static BOOL WINAPI load_compat_settings(INIT_ONCE *once, void *param, void **context)
+{
+    WCHAR key_name[INTERNET_MAX_HOST_NAME_LENGTH];
+    DWORD index = 0, name_size;
+    compat_config_t *new_entry;
+    compat_mode_t max_compat_mode;
+    HKEY key, host_key;
+    DWORD res;
+
+    static const WCHAR key_nameW[] = {
+        'S','o','f','t','w','a','r','e',
+        '\\','W','i','n','e',
+        '\\','M','S','H','T','M','L',
+        '\\','C','o','m','p','a','t','M','o','d','e',0};
+
+    /* @@ Wine registry key: HKCU\Software\Wine\MSHTML\CompatMode */
+    res = RegOpenKeyW(HKEY_CURRENT_USER, key_nameW, &key);
+    if(res != ERROR_SUCCESS)
+        return TRUE;
+
+    if(read_compat_mode(key, &max_compat_mode)) {
+        TRACE("Setting global max compat mode to %u\n", max_compat_mode);
+        global_max_compat_mode = max_compat_mode;
+    }
+
+    while(1) {
+        res = RegEnumKeyW(key, index, key_name, ARRAY_SIZE(key_name));
+        if(res == ERROR_NO_MORE_ITEMS)
+            break;
+        index++;
+        if(res != ERROR_SUCCESS) {
+            WARN("RegEnumKey failed: %u\n", GetLastError());
+            continue;
+        }
+
+        name_size = strlenW(key_name) + 1;
+        new_entry = heap_alloc(FIELD_OFFSET(compat_config_t, host[name_size]));
+        if(!new_entry)
+            continue;
+
+        new_entry->max_compat_mode = COMPAT_MODE_IE11;
+        memcpy(new_entry->host, key_name, name_size * sizeof(WCHAR));
+        list_add_tail(&compat_config, &new_entry->entry);
+
+        res = RegOpenKeyW(key, key_name, &host_key);
+        if(res != ERROR_SUCCESS)
+            continue;
+
+        if(read_compat_mode(host_key, &max_compat_mode)) {
+            TRACE("Setting max compat mode for %s to %u\n", debugstr_w(key_name), max_compat_mode);
+            new_entry->max_compat_mode = max_compat_mode;
+        }
+
+        RegCloseKey(host_key);
+    }
+
+    RegCloseKey(key);
+    return TRUE;
+}
+
+compat_mode_t get_max_compat_mode(IUri *uri)
+{
+    compat_config_t *iter;
+    size_t len, iter_len;
+    BSTR host;
+    HRESULT hres;
+
+    static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
+    InitOnceExecuteOnce(&init_once, load_compat_settings, NULL, NULL);
+
+    if(!uri)
+        return global_max_compat_mode;
+    hres = IUri_GetHost(uri, &host);
+    if(FAILED(hres))
+        return global_max_compat_mode;
+    len = SysStringLen(host);
+
+    LIST_FOR_EACH_ENTRY(iter, &compat_config, compat_config_t, entry) {
+        iter_len = strlenW(iter->host);
+        /* If configured host starts with '.', we also match subdomains */
+        if((len == iter_len || (iter->host[0] == '.' && len > iter_len))
+           && !memcmp(host + len - iter_len, iter->host, iter_len * sizeof(WCHAR))) {
+            TRACE("Found max mode %u\n", iter->max_compat_mode);
+            return iter->max_compat_mode;
+        }
+    }
+
+    SysFreeString(host);
+    TRACE("Using global max mode %u\n", global_max_compat_mode);
+    return global_max_compat_mode;
+}
+
 static void thread_detach(void)
 {
     thread_data_t *thread_data;
@@ -132,9 +249,17 @@ static void free_strings(void)
 
 static void process_detach(void)
 {
+    compat_config_t *config;
+
     close_gecko();
     release_typelib();
 
+    while(!list_empty(&compat_config)) {
+        config = LIST_ENTRY(list_head(&compat_config), compat_config_t, entry);
+        list_remove(&config->entry);
+        heap_free(config);
+    }
+
     if(shdoclc)
         FreeLibrary(shdoclc);
     if(mshtml_tls != TLS_OUT_OF_INDEXES)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index ddc8df5..89a56bd 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -1167,6 +1167,8 @@ void remove_target_tasks(LONG) DECLSPEC_HIDDEN;
 HRESULT set_task_timer(HTMLInnerWindow*,LONG,BOOL,IDispatch*,LONG*) DECLSPEC_HIDDEN;
 HRESULT clear_task_timer(HTMLInnerWindow*,DWORD) DECLSPEC_HIDDEN;
 
+BOOL parse_compat_version(const WCHAR*,compat_mode_t*) DECLSPEC_HIDDEN;
+
 const char *debugstr_mshtml_guid(const GUID*) DECLSPEC_HIDDEN;
 
 DEFINE_GUID(CLSID_AboutProtocol, 0x3050F406, 0x98B5, 0x11CF, 0xBB,0x82, 0x00,0xAA,0x00,0xBD,0xCE,0x0B);
@@ -1337,6 +1339,7 @@ static inline VARIANT_BOOL variant_bool(BOOL b)
 extern void *call_thiscall_func;
 #endif
 
+compat_mode_t get_max_compat_mode(IUri*) DECLSPEC_HIDDEN;
 UINT cp_from_charset_string(BSTR) DECLSPEC_HIDDEN;
 BSTR charset_string_from_cp(UINT) DECLSPEC_HIDDEN;
 HINSTANCE get_shdoclc(void) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c
index dd46dd8..1a1cfe3 100644
--- a/dlls/mshtml/mutation.c
+++ b/dlls/mshtml/mutation.c
@@ -377,6 +377,8 @@ compat_mode_t lock_document_mode(HTMLDocumentNode *doc)
 
 static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode, BOOL lock)
 {
+    compat_mode_t max_compat_mode;
+
     if(doc->document_mode_locked) {
         WARN("attempting to set document mode %d on locked document %p\n", document_mode, doc);
         return;
@@ -384,35 +386,31 @@ static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode
 
     TRACE("%p: %d\n", doc, document_mode);
 
+    max_compat_mode = doc->window && doc->window->base.outer_window
+        ? get_max_compat_mode(doc->window->base.outer_window->uri)
+        : COMPAT_MODE_IE11;
+    if(max_compat_mode < document_mode) {
+        WARN("Tried to set compat mode %u higher than maximal configured %u\n",
+             document_mode, max_compat_mode);
+        document_mode = max_compat_mode;
+    }
+
     doc->document_mode = document_mode;
     if(lock)
         lock_document_mode(doc);
 }
 
-static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
+BOOL parse_compat_version(const WCHAR *version_string, compat_mode_t *r)
 {
-    int v = 0;
-
-    static const WCHAR ie_eqW[] = {'I','E','='};
-    static const WCHAR edgeW[] = {'e','d','g','e',0};
+    DWORD version = 0;
+    const WCHAR *p;
 
-    TRACE("%s\n", debugstr_w(p));
-
-    if(strncmpiW(ie_eqW, p, ARRAY_SIZE(ie_eqW)))
+    for(p = version_string; '0' <= *p && *p <= '9'; p++)
+        version = version * 10 + *p-'0';
+    if(*p || p == version_string)
         return FALSE;
-    p += 3;
 
-    if(!strcmpiW(p, edgeW)) {
-        *r = COMPAT_MODE_IE11;
-        return TRUE;
-    }
-
-    while('0' <= *p && *p <= '9')
-        v = v*10 + *(p++)-'0';
-    if(*p || !v)
-        return FALSE;
-
-    switch(v){
+    switch(version){
     case 5:
     case 6:
         *r = COMPAT_MODE_IE5;
@@ -430,12 +428,30 @@ static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
         *r = COMPAT_MODE_IE10;
         break;
     default:
-        *r = v < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
+        *r = version < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
     }
-
     return TRUE;
 }
 
+static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
+{
+    static const WCHAR ie_eqW[] = {'I','E','='};
+    static const WCHAR edgeW[] = {'e','d','g','e',0};
+
+    TRACE("%s\n", debugstr_w(p));
+
+    if(strncmpiW(ie_eqW, p, ARRAY_SIZE(ie_eqW)))
+        return FALSE;
+    p += 3;
+
+    if(!strcmpiW(p, edgeW)) {
+        *r = COMPAT_MODE_IE11;
+        return TRUE;
+    }
+
+    return parse_compat_version(p, r);
+}
+
 void process_document_response_headers(HTMLDocumentNode *doc, IBinding *binding)
 {
     IWinInetHttpInfo *http_info;




More information about the wine-cvs mailing list