mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 06:23:45 +00:00
Merge pull request #1310 from lightpanda-io/zigdom-named-access
Named Access on the Window Object
This commit is contained in:
@@ -74,26 +74,23 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
|
||||
|
||||
const env = self.env;
|
||||
const isolate = env.isolate;
|
||||
const arena = self.context_arena.allocator();
|
||||
|
||||
var v8_context: v8.Context = blk: {
|
||||
var temp_scope: v8.HandleScope = undefined;
|
||||
v8.HandleScope.init(&temp_scope, isolate);
|
||||
defer temp_scope.deinit();
|
||||
|
||||
if (comptime IS_DEBUG) {
|
||||
// Getting this into the snapshot is tricky (anything involving the
|
||||
// global is tricky). Easier to do here, and in debug mode, we're
|
||||
// fine with paying the small perf hit.
|
||||
const js_global = v8.FunctionTemplate.initDefault(isolate);
|
||||
const global_template = js_global.getInstanceTemplate();
|
||||
// Creates a global template that inherits from Window.
|
||||
const global_template = @import("Snapshot.zig").createGlobalTemplate(isolate, env.templates);
|
||||
|
||||
global_template.setNamedProperty(v8.NamedPropertyHandlerConfiguration{
|
||||
.getter = unknownPropertyCallback,
|
||||
.flags = v8.PropertyHandlerFlags.NonMasking | v8.PropertyHandlerFlags.OnlyInterceptStrings,
|
||||
}, null);
|
||||
}
|
||||
// Add the named property handler
|
||||
global_template.setNamedProperty(v8.NamedPropertyHandlerConfiguration{
|
||||
.getter = unknownPropertyCallback,
|
||||
.flags = v8.PropertyHandlerFlags.NonMasking | v8.PropertyHandlerFlags.OnlyInterceptStrings,
|
||||
}, null);
|
||||
|
||||
const context_local = v8.Context.init(isolate, null, null);
|
||||
const context_local = v8.Context.init(isolate, global_template, null);
|
||||
const v8_context = v8.Persistent(v8.Context).init(isolate, context_local).castToContext();
|
||||
break :blk v8_context;
|
||||
};
|
||||
@@ -124,7 +121,7 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
|
||||
.handle_scope = handle_scope,
|
||||
.script_manager = &page._script_manager,
|
||||
.call_arena = page.call_arena,
|
||||
.arena = self.context_arena.allocator(),
|
||||
.arena = arena,
|
||||
};
|
||||
|
||||
var context = &self.context.?;
|
||||
@@ -159,9 +156,9 @@ pub fn resumeExecution(self: *const ExecutionWorld) void {
|
||||
|
||||
pub fn unknownPropertyCallback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
||||
const info = v8.PropertyCallbackInfo.initFromV8(raw_info);
|
||||
const context = Context.fromIsolate(info.getIsolate());
|
||||
|
||||
const property = context.valueToString(.{ .handle = c_name.? }, .{}) catch "???";
|
||||
const context = Context.fromIsolate(info.getIsolate());
|
||||
const maybe_property: ?[]u8 = context.valueToString(.{ .handle = c_name.? }, .{}) catch null;
|
||||
|
||||
const ignored = std.StaticStringMap(void).initComptime(.{
|
||||
.{ "process", {} },
|
||||
@@ -185,12 +182,25 @@ pub fn unknownPropertyCallback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C
|
||||
.{ "CLOSURE_FLAGS", {} },
|
||||
});
|
||||
|
||||
if (!ignored.has(property)) {
|
||||
log.debug(.unknown_prop, "unkown global property", .{
|
||||
.info = "but the property can exist in pure JS",
|
||||
.stack = context.stackTrace() catch "???",
|
||||
.property = property,
|
||||
});
|
||||
if (maybe_property) |prop| {
|
||||
if (!ignored.has(prop)) {
|
||||
const document = context.page.document;
|
||||
|
||||
if (document.getElementById(prop)) |el| {
|
||||
const js_value = context.zigValueToJs(el, .{}) catch {
|
||||
return v8.Intercepted.No;
|
||||
};
|
||||
|
||||
info.getReturnValue().set(js_value);
|
||||
return v8.Intercepted.Yes;
|
||||
}
|
||||
|
||||
log.debug(.unknown_prop, "unknown global property", .{
|
||||
.info = "but the property can exist in pure JS",
|
||||
.stack = context.stackTrace() catch "???",
|
||||
.property = prop,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return v8.Intercepted.No;
|
||||
|
||||
@@ -116,6 +116,19 @@ pub fn tryCallWithThis(self: *const Function, comptime T: type, this: anytype, a
|
||||
pub fn callWithThis(self: *const Function, comptime T: type, this: anytype, args: anytype) !T {
|
||||
const context = self.context;
|
||||
|
||||
// When we're calling a function from within JavaScript itself, this isn't
|
||||
// necessary. We're within a Caller instantiation, which will already have
|
||||
// incremented the call_depth and it won't decrement it until the Caller is
|
||||
// done.
|
||||
// But some JS functions are initiated from Zig code, and not v8. For
|
||||
// example, Observers, some event and window callbacks. In those cases, we
|
||||
// need to increase the call_depth so that the call_arena remains valid for
|
||||
// the duration of the function call. If we don't do this, the call_arena
|
||||
// will be reset after each statement of the function which executes Zig code.
|
||||
const call_depth = context.call_depth;
|
||||
context.call_depth = call_depth + 1;
|
||||
defer context.call_depth = call_depth;
|
||||
|
||||
const js_this = try context.valueToExistingObject(this);
|
||||
|
||||
const aargs = if (comptime @typeInfo(@TypeOf(args)) == .null) struct {}{} else args;
|
||||
|
||||
@@ -54,7 +54,7 @@ pub fn set(self: Object, key: []const u8, value: anytype, opts: SetOpts) error{
|
||||
const context = self.context;
|
||||
|
||||
const js_key = v8.String.initUtf8(context.isolate, key);
|
||||
const js_value = try context.zigValueToJs(value);
|
||||
const js_value = try context.zigValueToJs(value, .{});
|
||||
|
||||
const res = self.js_obj.defineOwnProperty(context.v8_context, js_key.toName(), js_value, @bitCast(opts)) orelse false;
|
||||
if (!res) {
|
||||
|
||||
@@ -113,6 +113,17 @@ fn isValid(self: Snapshot) bool {
|
||||
return v8.SnapshotCreator.startupDataIsValid(self.startup_data);
|
||||
}
|
||||
|
||||
pub fn createGlobalTemplate(isolate: v8.Isolate, templates: []const v8.FunctionTemplate) v8.ObjectTemplate {
|
||||
// Set up the global template to inherit from Window's template
|
||||
// This way the global object gets all Window properties through inheritance
|
||||
const js_global = v8.FunctionTemplate.initDefault(isolate);
|
||||
js_global.setClassName(v8.String.initUtf8(isolate, "Window"));
|
||||
// Find Window in JsApis by name (avoids circular import)
|
||||
const window_index = comptime bridge.JsApiLookup.getId(Window.JsApi);
|
||||
js_global.inherit(templates[window_index]);
|
||||
return js_global.getInstanceTemplate();
|
||||
}
|
||||
|
||||
pub fn create(allocator: Allocator) !Snapshot {
|
||||
var external_references = collectExternalReferences();
|
||||
|
||||
@@ -154,14 +165,7 @@ pub fn create(allocator: Allocator) !Snapshot {
|
||||
|
||||
// Set up the global template to inherit from Window's template
|
||||
// This way the global object gets all Window properties through inheritance
|
||||
const js_global = v8.FunctionTemplate.initDefault(isolate);
|
||||
js_global.setClassName(v8.String.initUtf8(isolate, "Window"));
|
||||
|
||||
// Find Window in JsApis by name (avoids circular import)
|
||||
const window_index = comptime bridge.JsApiLookup.getId(Window.JsApi);
|
||||
js_global.inherit(templates[window_index]);
|
||||
|
||||
const global_template = js_global.getInstanceTemplate();
|
||||
const global_template = createGlobalTemplate(isolate, templates[0..]);
|
||||
|
||||
const context = v8.Context.init(isolate, global_template, null);
|
||||
context.enter();
|
||||
|
||||
26
src/browser/tests/window/named_access.html
Normal file
26
src/browser/tests/window/named_access.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../testing.js"></script>
|
||||
|
||||
<div id=i></div>
|
||||
<div id=testDiv></div>
|
||||
<span id=mySpan></span>
|
||||
<p id=paragraph></p>
|
||||
|
||||
<script id=named_access_global>
|
||||
testing.expectEqual('i', i.id);
|
||||
testing.expectEqual('testDiv',testDiv.id);
|
||||
testing.expectEqual('mySpan', mySpan.id);
|
||||
testing.expectEqual('paragraph', paragraph.id);
|
||||
</script>
|
||||
|
||||
<script id=named_access_window>
|
||||
testing.expectEqual('i', window.i.id);
|
||||
testing.expectEqual('testDiv', window.testDiv.id);
|
||||
testing.expectEqual('mySpan', window.mySpan.id);
|
||||
testing.expectEqual('paragraph', window.paragraph.id);
|
||||
</script>
|
||||
|
||||
<script id=named_access_shadowing>
|
||||
const i = 100;
|
||||
testing.expectEqual(100, i);
|
||||
</script>
|
||||
Reference in New Issue
Block a user