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