mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Add dummy PerformanceObserver
Adds a dummy PerformanceObserver. Only the supportedEntryTypes static attribute is supported, and it currently returns an empty array. This hopefully prevents code from trying to use it. For example, before using it, reddit checks if specific types are supported and, if not, doesn't use it. This introduced complexity in the js runtime. Our current approach to attributes only works with primitive types. Non-primitive types can't be attached to a FunctionTemplate (v8 will crash saying only primitive types can be set). Plus, all non primitive types require a context to create anyways. We now detect "primitive" attributes and "complex" attributes. Primitive attributes are setup as before. Complex attributes are setup per-context, requiring another loop through our types to detect & setup on each context creation.
This commit is contained in:
@@ -28,6 +28,8 @@ const IntersectionObserver = @import("intersection_observer.zig");
|
|||||||
const DOMParser = @import("dom_parser.zig").DOMParser;
|
const DOMParser = @import("dom_parser.zig").DOMParser;
|
||||||
const TreeWalker = @import("tree_walker.zig").TreeWalker;
|
const TreeWalker = @import("tree_walker.zig").TreeWalker;
|
||||||
const NodeFilter = @import("node_filter.zig").NodeFilter;
|
const NodeFilter = @import("node_filter.zig").NodeFilter;
|
||||||
|
const Performance = @import("performance.zig").Performance;
|
||||||
|
const PerformanceObserver = @import("performance_observer.zig").PerformanceObserver;
|
||||||
|
|
||||||
pub const Interfaces = .{
|
pub const Interfaces = .{
|
||||||
DOMException,
|
DOMException,
|
||||||
@@ -44,4 +46,6 @@ pub const Interfaces = .{
|
|||||||
DOMParser,
|
DOMParser,
|
||||||
TreeWalker,
|
TreeWalker,
|
||||||
NodeFilter,
|
NodeFilter,
|
||||||
|
Performance,
|
||||||
|
PerformanceObserver,
|
||||||
};
|
};
|
||||||
|
|||||||
34
src/browser/dom/performance_observer.zig
Normal file
34
src/browser/dom/performance_observer.zig
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver
|
||||||
|
pub const PerformanceObserver = struct {
|
||||||
|
pub const _supportedEntryTypes = [0][]const u8{};
|
||||||
|
};
|
||||||
|
|
||||||
|
const testing = @import("../../testing.zig");
|
||||||
|
test "Browser.DOM.PerformanceObserver" {
|
||||||
|
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
|
||||||
|
defer runner.deinit();
|
||||||
|
|
||||||
|
try runner.testCases(&.{
|
||||||
|
.{ "PerformanceObserver.supportedEntryTypes.length", "0" },
|
||||||
|
}, .{});
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@ const Navigator = @import("navigator.zig").Navigator;
|
|||||||
const History = @import("history.zig").History;
|
const History = @import("history.zig").History;
|
||||||
const Location = @import("location.zig").Location;
|
const Location = @import("location.zig").Location;
|
||||||
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
||||||
const Performance = @import("performance.zig").Performance;
|
|
||||||
|
|
||||||
pub const Interfaces = .{
|
pub const Interfaces = .{
|
||||||
HTMLDocument,
|
HTMLDocument,
|
||||||
@@ -37,6 +36,5 @@ pub const Interfaces = .{
|
|||||||
History,
|
History,
|
||||||
Location,
|
Location,
|
||||||
MediaQueryList,
|
MediaQueryList,
|
||||||
Performance,
|
|
||||||
@import("screen.zig").Interfaces,
|
@import("screen.zig").Interfaces,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const Crypto = @import("../crypto/crypto.zig").Crypto;
|
|||||||
const Console = @import("../console/console.zig").Console;
|
const Console = @import("../console/console.zig").Console;
|
||||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||||
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
||||||
const Performance = @import("performance.zig").Performance;
|
const Performance = @import("../dom/performance.zig").Performance;
|
||||||
const CSSStyleDeclaration = @import("../cssom/css_style_declaration.zig").CSSStyleDeclaration;
|
const CSSStyleDeclaration = @import("../cssom/css_style_declaration.zig").CSSStyleDeclaration;
|
||||||
const CustomElementRegistry = @import("../webcomponents/custom_element_registry.zig").CustomElementRegistry;
|
const CustomElementRegistry = @import("../webcomponents/custom_element_registry.zig").CustomElementRegistry;
|
||||||
const Screen = @import("screen.zig").Screen;
|
const Screen = @import("screen.zig").Screen;
|
||||||
|
|||||||
@@ -337,6 +337,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
const env = self.env;
|
const env = self.env;
|
||||||
const isolate = env.isolate;
|
const isolate = env.isolate;
|
||||||
const Global = @TypeOf(global.*);
|
const Global = @TypeOf(global.*);
|
||||||
|
const templates = &self.env.templates;
|
||||||
|
|
||||||
var v8_context: v8.Context = blk: {
|
var v8_context: v8.Context = blk: {
|
||||||
var temp_scope: v8.HandleScope = undefined;
|
var temp_scope: v8.HandleScope = undefined;
|
||||||
@@ -351,7 +352,6 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
|
|
||||||
// All the FunctionTemplates that we created and setup in Env.init
|
// All the FunctionTemplates that we created and setup in Env.init
|
||||||
// are now going to get associated with our global instance.
|
// are now going to get associated with our global instance.
|
||||||
const templates = &self.env.templates;
|
|
||||||
inline for (Types, 0..) |s, i| {
|
inline for (Types, 0..) |s, i| {
|
||||||
const Struct = s.defaultValue().?;
|
const Struct = s.defaultValue().?;
|
||||||
const class_name = v8.String.initUtf8(isolate, comptime classNameForStruct(Struct));
|
const class_name = v8.String.initUtf8(isolate, comptime classNameForStruct(Struct));
|
||||||
@@ -463,6 +463,38 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Primitive attributes are set directly on the FunctionTemplate
|
||||||
|
// when we setup the environment. But we cannot set more complex
|
||||||
|
// types (v8 will crash).
|
||||||
|
//
|
||||||
|
// Plus, just to create more complex types, we always need a
|
||||||
|
// context, i.e. an Array has to have a Context to exist.
|
||||||
|
//
|
||||||
|
// As far as I can tell, getting the FunctionTemplate's object
|
||||||
|
// and setting values directly on it, for each context, is the
|
||||||
|
// way to do this.
|
||||||
|
inline for (Types, 0..) |s, i| {
|
||||||
|
const Struct = s.defaultValue().?;
|
||||||
|
inline for (@typeInfo(Struct).@"struct".decls) |declaration| {
|
||||||
|
const name = declaration.name;
|
||||||
|
if (comptime name[0] == '_') {
|
||||||
|
const value = @field(Struct, name);
|
||||||
|
|
||||||
|
if (comptime isComplexAttributeType(@typeInfo(@TypeOf(value)))) {
|
||||||
|
const js_obj = templates[i].getFunction(v8_context).toObject();
|
||||||
|
const js_name = v8.String.initUtf8(isolate, name[1..]).toName();
|
||||||
|
const js_val = try js_context.zigValueToJs(value);
|
||||||
|
if (!js_obj.setValue(v8_context, js_name, js_val)) {
|
||||||
|
log.fatal(.app, "set class attribute", .{
|
||||||
|
.@"struct" = @typeName(Struct),
|
||||||
|
.name = name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ = try js_context._mapZigInstanceToJs(v8_context.getGlobal(), global);
|
_ = try js_context._mapZigInstanceToJs(v8_context.getGlobal(), global);
|
||||||
return js_context;
|
return js_context;
|
||||||
}
|
}
|
||||||
@@ -1809,7 +1841,9 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
if (comptime name[0] == '_') {
|
if (comptime name[0] == '_') {
|
||||||
switch (@typeInfo(@TypeOf(@field(Struct, name)))) {
|
switch (@typeInfo(@TypeOf(@field(Struct, name)))) {
|
||||||
.@"fn" => generateMethod(Struct, name, isolate, template_proto),
|
.@"fn" => generateMethod(Struct, name, isolate, template_proto),
|
||||||
else => generateAttribute(Struct, name, isolate, template, template_proto),
|
else => |ti| if (!comptime isComplexAttributeType(ti)) {
|
||||||
|
generateAttribute(Struct, name, isolate, template, template_proto);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
} else if (comptime std.mem.startsWith(u8, name, "get_")) {
|
} else if (comptime std.mem.startsWith(u8, name, "get_")) {
|
||||||
generateProperty(Struct, name[4..], isolate, template_proto);
|
generateProperty(Struct, name[4..], isolate, template_proto);
|
||||||
@@ -1930,7 +1964,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
// apply it both to the type itself
|
// apply it both to the type itself
|
||||||
template.set(js_name, js_value, v8.PropertyAttribute.ReadOnly + v8.PropertyAttribute.DontDelete);
|
template.set(js_name, js_value, v8.PropertyAttribute.ReadOnly + v8.PropertyAttribute.DontDelete);
|
||||||
|
|
||||||
// andto instances of the type
|
// and to instances of the type
|
||||||
template_proto.set(js_name, js_value, v8.PropertyAttribute.ReadOnly + v8.PropertyAttribute.DontDelete);
|
template_proto.set(js_name, js_value, v8.PropertyAttribute.ReadOnly + v8.PropertyAttribute.DontDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2396,6 +2430,20 @@ fn isEmpty(comptime T: type) bool {
|
|||||||
return @typeInfo(T) != .@"opaque" and @sizeOf(T) == 0 and @hasDecl(T, "js_legacy_factory") == false;
|
return @typeInfo(T) != .@"opaque" and @sizeOf(T) == 0 and @hasDecl(T, "js_legacy_factory") == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attributes that return a primitive type are setup directly on the
|
||||||
|
// FunctionTemplate when the Env is setup. More complex types need a v8.Context
|
||||||
|
// and cannot be set directly on the FunctionTemplate.
|
||||||
|
// We default to saying types are primitives because that's mostly what
|
||||||
|
// we have. If we add a new complex type that isn't explictly handled here,
|
||||||
|
// we'll get a compiler error in simpleZigValueToJs, and can then explicitly
|
||||||
|
// add the type here.
|
||||||
|
fn isComplexAttributeType(ti: std.builtin.Type) bool {
|
||||||
|
return switch (ti) {
|
||||||
|
.array => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Responsible for calling Zig functions from JS invokations. This could
|
// Responsible for calling Zig functions from JS invokations. This could
|
||||||
// probably just contained in ExecutionWorld, but having this specific logic, which
|
// probably just contained in ExecutionWorld, but having this specific logic, which
|
||||||
// is somewhat repetitive between constructors, functions, getters, etc contained
|
// is somewhat repetitive between constructors, functions, getters, etc contained
|
||||||
|
|||||||
Reference in New Issue
Block a user