add PerformanceEntry and PerformanceMark

This commit is contained in:
Muki Kiboigo
2025-06-23 09:25:40 -07:00
parent bdb2338b5b
commit 6b651cd5e4
3 changed files with 124 additions and 3 deletions

View File

@@ -28,7 +28,6 @@ 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; const PerformanceObserver = @import("performance_observer.zig").PerformanceObserver;
pub const Interfaces = .{ pub const Interfaces = .{
@@ -46,6 +45,6 @@ pub const Interfaces = .{
DOMParser, DOMParser,
TreeWalker, TreeWalker,
NodeFilter, NodeFilter,
Performance, @import("performance.zig").Interfaces,
PerformanceObserver, PerformanceObserver,
}; };

View File

@@ -20,6 +20,19 @@ const std = @import("std");
const parser = @import("../netsurf.zig"); const parser = @import("../netsurf.zig");
const EventTarget = @import("../dom/event_target.zig").EventTarget; const EventTarget = @import("../dom/event_target.zig").EventTarget;
const Env = @import("../env.zig").Env;
const Page = @import("../page.zig").Page;
pub const Interfaces = .{
Performance,
PerformanceEntry,
PerformanceMark,
};
const MarkOptions = struct {
detail: ?Env.JsObject = null,
start_time: ?f64 = null,
};
// https://developer.mozilla.org/en-US/docs/Web/API/Performance // https://developer.mozilla.org/en-US/docs/Web/API/Performance
pub const Performance = struct { pub const Performance = struct {
@@ -52,6 +65,93 @@ pub const Performance = struct {
pub fn _now(self: *Performance) f64 { pub fn _now(self: *Performance) f64 {
return limitedResolutionMs(self.time_origin.read()); return limitedResolutionMs(self.time_origin.read());
} }
pub fn _mark(_: *Performance, name: []const u8, _options: ?MarkOptions, page: *Page) !PerformanceMark {
const mark: PerformanceMark = try .constructor(name, _options, page);
// TODO: Should store this in an entries list
return mark;
}
};
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry
pub const PerformanceEntry = struct {
const PerformanceEntryType = enum {
element,
event,
first_input,
largest_contentful_paint,
layout_shift,
long_animation_frame,
longtask,
mark,
measure,
navigation,
paint,
resource,
taskattribution,
visibility_state,
pub fn toString(self: PerformanceEntryType) []const u8 {
return switch (self) {
.first_input => "first-input",
.largest_contentful_paint => "largest-contentful-paint",
.layout_shift => "layout-shift",
.long_animation_frame => "long-animation-frame",
.visibility_state => "visibility-state",
else => @tagName(self),
};
}
};
duration: f64 = 0.0,
entry_type: PerformanceEntryType,
name: []const u8,
start_time: f64 = 0.0,
pub fn get_duration(self: *const PerformanceEntry) f64 {
return self.duration;
}
pub fn get_entryType(self: *const PerformanceEntry) PerformanceEntryType {
return self.entry_type;
}
pub fn get_name(self: *const PerformanceEntry) []const u8 {
return self.name;
}
pub fn get_startTime(self: *const PerformanceEntry) f64 {
return self.start_time;
}
};
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceMark
pub const PerformanceMark = struct {
pub const prototype = *PerformanceEntry;
proto: PerformanceEntry,
detail: ?Env.JsObject,
pub fn constructor(name: []const u8, _options: ?MarkOptions, page: *Page) !PerformanceMark {
const perf = &page.window.performance;
const options = _options orelse MarkOptions{};
const start_time = options.start_time orelse perf._now();
const detail = if (options.detail) |d| try d.persist() else null;
if (start_time < 0.0) {
return error.TypeError;
}
const duped_name = try page.arena.dupe(u8, name);
const proto = PerformanceEntry{ .name = duped_name, .entry_type = .mark, .start_time = start_time };
return .{ .proto = proto, .detail = detail };
}
pub fn get_detail(self: *const PerformanceMark) ?Env.JsObject {
return self.detail;
}
}; };
const testing = @import("./../../testing.zig"); const testing = @import("./../../testing.zig");
@@ -85,3 +185,19 @@ test "Performance: now" {
// Check resolution // Check resolution
try testing.expectDelta(@rem(after * std.time.us_per_ms, 100.0), 0.0, 0.1); try testing.expectDelta(@rem(after * std.time.us_per_ms, 100.0), 0.0, 0.1);
} }
test "Browser.Performance.Mark" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "let performance = window.performance", "undefined" },
.{ "performance instanceof Performance", "true" },
.{ "let mark = performance.mark(\"start\")", "undefined" },
.{ "mark instanceof PerformanceMark", "true" },
.{ "mark.name", "start" },
.{ "mark.entryType", "mark" },
.{ "mark.duration", "0" },
.{ "mark.detail", "null" },
}, .{});
}

View File

@@ -2201,7 +2201,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
const T = @TypeOf(value); const T = @TypeOf(value);
switch (@typeInfo(T)) { switch (@typeInfo(T)) {
.void, .bool, .int, .comptime_int, .float, .comptime_float => { .void, .bool, .int, .comptime_int, .float, .comptime_float, .@"enum" => {
// Need to do this to keep the compiler happy // Need to do this to keep the compiler happy
// simpleZigValueToJs handles all of these cases. // simpleZigValueToJs handles all of these cases.
unreachable; unreachable;
@@ -3084,6 +3084,12 @@ fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bool)
} }
}, },
.@"union" => return simpleZigValueToJs(isolate, std.meta.activeTag(value), fail), .@"union" => return simpleZigValueToJs(isolate, std.meta.activeTag(value), fail),
.@"enum" => {
const T = @TypeOf(value);
if (@hasDecl(T, "toString")) {
return simpleZigValueToJs(isolate, value.toString(), fail);
}
},
else => {}, else => {},
} }
if (fail) { if (fail) {