Module: wine Branch: master Commit: 551e5a77e24d7b93808b127d16a97d65288e2864 URL: https://source.winehq.org/git/wine.git/?a=commit;h=551e5a77e24d7b93808b127d1...
Author: Jacek Caban jacek@codeweavers.com Date: Thu May 10 19:19:56 2018 +0200
jscript: Added Object.getOwnPropertyDescriptor implementation.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/jscript/dispex.c | 32 +++++++++++++++ dlls/jscript/jscript.h | 7 ++++ dlls/jscript/object.c | 83 ++++++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/documentmode.js | 4 ++ dlls/mshtml/tests/es5.js | 43 +++++++++++++++++--- 5 files changed, 163 insertions(+), 6 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index d3f345a..5ba5b70 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1614,3 +1614,35 @@ HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret) *ret = prop && (prop->flags & PROPF_ENUMERABLE) && prop->type != PROP_PROTREF; return S_OK; } + +HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only, + property_desc_t *desc) +{ + dispex_prop_t *prop; + HRESULT hres; + + hres = find_prop_name(obj, string_hash(name), name, &prop); + if(FAILED(hres)) + return hres; + + if(!prop) + return DISP_E_UNKNOWNNAME; + + memset(desc, 0, sizeof(*desc)); + + switch(prop->type) { + case PROP_BUILTIN: + case PROP_JSVAL: + if(!flags_only) { + hres = prop_get(obj, prop, &desc->value); + if(FAILED(hres)) + return hres; + } + break; + default: + return DISP_E_UNKNOWNNAME; + } + + desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE); + return S_OK; +} diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 9c28da0..ab7d634 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -50,6 +50,7 @@ typedef struct _jsval_t jsval_t; typedef struct _jsstr_t jsstr_t; typedef struct _script_ctx_t script_ctx_t; typedef struct _dispex_prop_t dispex_prop_t; +typedef struct _property_desc_t property_desc_t;
typedef struct { void **blocks; @@ -292,6 +293,7 @@ HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*) DECLSPEC_HIDDEN; HRESULT disp_delete(IDispatch*,DISPID,BOOL*) DECLSPEC_HIDDEN; HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*) DECLSPEC_HIDDEN; HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD) DECLSPEC_HIDDEN; +HRESULT jsdisp_get_own_property(jsdisp_t*,const WCHAR*,BOOL,property_desc_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_is_own_prop(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN; HRESULT jsdisp_is_enumerable(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
@@ -376,6 +378,11 @@ typedef struct {
#include "jsval.h"
+struct _property_desc_t { + unsigned flags; + jsval_t value; +}; + typedef struct { EXCEPINFO ei; jsval_t val; diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index de09060..72365c7 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -32,8 +32,16 @@ static const WCHAR propertyIsEnumerableW[] = {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0}; static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
+static const WCHAR getOwnPropertyDescriptorW[] = + {'g','e','t','O','w','n','P','r','o','p','e','r','t','y','D','e','s','c','r','i','p','t','o','r',0}; + static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0};
+static const WCHAR configurableW[] = {'c','o','n','f','i','g','u','r','a','b','l','e',0}; +static const WCHAR enumerableW[] = {'e','n','u','m','e','r','a','b','l','e',0}; +static const WCHAR valueW[] = {'v','a','l','u','e',0}; +static const WCHAR writableW[] = {'w','r','i','t','a','b','l','e',0}; + static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -252,6 +260,79 @@ static const builtin_info_t ObjectInst_info = { NULL };
+static void release_property_descriptor(property_desc_t *desc) +{ + jsval_release(desc->value); +} + +static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + property_desc_t prop_desc; + jsdisp_t *obj, *desc_obj; + const WCHAR *name; + jsstr_t *name_str; + HRESULT hres; + + TRACE("\n"); + + if(argc < 1 || !is_object_instance(argv[0])) + return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); + obj = to_jsdisp(get_object(argv[0])); + if(!obj) { + FIXME("not implemented non-JS object\n"); + return E_NOTIMPL; + } + + hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name); + if(FAILED(hres)) + return hres; + + hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc); + jsstr_release(name_str); + if(hres == DISP_E_UNKNOWNNAME) { + if(r) *r = jsval_undefined(); + return S_OK; + } + if(FAILED(hres)) + return hres; + + hres = create_object(ctx, NULL, &desc_obj); + if(FAILED(hres)) + return hres; + + hres = jsdisp_propput_name(desc_obj, valueW, prop_desc.value); + if(SUCCEEDED(hres)) + hres = jsdisp_propput_name(desc_obj, writableW, + jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE))); + if(SUCCEEDED(hres)) + hres = jsdisp_propput_name(desc_obj, enumerableW, + jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE))); + if(SUCCEEDED(hres)) + hres = jsdisp_propput_name(desc_obj, configurableW, + jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE))); + + release_property_descriptor(&prop_desc); + if(SUCCEEDED(hres) && r) + *r = jsval_obj(desc_obj); + else + jsdisp_release(desc_obj); + return hres; +} + +static const builtin_prop_t ObjectConstr_props[] = { + {getOwnPropertyDescriptorW, Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2} +}; + +static const builtin_info_t ObjectConstr_info = { + JSCLASS_FUNCTION, + DEFAULT_FUNCTION_VALUE, + sizeof(ObjectConstr_props)/sizeof(*ObjectConstr_props), + ObjectConstr_props, + NULL, + NULL +}; + static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -303,7 +384,7 @@ HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdi { static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
- return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, NULL, PROPF_CONSTR, + return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, &ObjectConstr_info, PROPF_CONSTR, object_prototype, ret); }
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3fbb2fb..1525b09 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -140,6 +140,10 @@ function test_javascript() { test_exposed("toISOString", Date.prototype, v >= 9); test_exposed("isArray", Array, v >= 9); test_exposed("indexOf", Array.prototype, v >= 9); + /* FIXME: IE8 implements weird semi-functional property descriptors. */ + if(v != 8) { + test_exposed("getOwnPropertyDescriptor", Object, v >= 8); + }
test_parses("if(false) { o.default; }", v >= 9); test_parses("if(false) { o.with; }", v >= 9); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index d539557..efdfb0a 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -28,8 +28,6 @@ function test_date_now() { }
function test_toISOString() { - var s; - function expect(date, expected) { var s = date.toISOString(); ok(s === expected, "toISOString returned " + s + " expected " + expected); @@ -53,8 +51,6 @@ function test_toISOString() { expect(new Date(-6216721920000100), "-195031-12-03T23:59:59.900Z"); expect(new Date(1092830912830100), "+036600-06-07T22:27:10.100Z");
- trace("" + 0xdeadbeef); - expect_exception(function() { new Date(NaN).toISOString(); }); expect_exception(function() { new Date(31494784780800001).toISOString(); });
@@ -147,10 +143,47 @@ function test_identifier_keywords() { next_test(); }
+function test_own_data_prop_desc(obj, prop, expected_writable, expected_enumerable, + expected_configurable) { + var desc = Object.getOwnPropertyDescriptor(obj, prop); + ok("value" in desc, "value is not in desc"); + ok(desc.value === obj[prop], "desc.value = " + desc.value + " expected " + obj[prop]); + ok(desc.writable === expected_writable, "desc(" + prop + ").writable = " + desc.writable + + " expected " + expected_writable); + ok(desc.enumerable === expected_enumerable, "desc.enumerable = " + desc.enumerable + + " expected " + expected_enumerable); + ok(desc.configurable === expected_configurable, "desc.configurable = " + desc.configurable + + " expected " + expected_configurable); +} + +function test_getOwnPropertyDescriptor() { + var obj; + + obj = { test: 1 }; + test_own_data_prop_desc(obj, "test", true, true, true); + + test_own_data_prop_desc(Object, "getOwnPropertyDescriptor", true, false, true); + test_own_data_prop_desc(Math, "PI", false, false, false); + + var obj = new String(); + ok(Object.getOwnPropertyDescriptor(obj, "slice") === undefined, + "getOwnPropertyDescriptor(slice) did not return undefined"); + test_own_data_prop_desc(String.prototype, "slice", true, false, true); + + obj = new Array(); + test_own_data_prop_desc(obj, "length", true, false, false); + + obj = /test/; + test_own_data_prop_desc(obj, "lastIndex", true, false, false); + + next_test(); +} + var tests = [ test_date_now, test_toISOString, test_indexOf, test_isArray, - test_identifier_keywords + test_identifier_keywords, + test_getOwnPropertyDescriptor ];