webapi: cookie-averse documents; HTMLElement.accessKeyLabel

Fixes two WPT files:

- /html/dom/documents/resource-metadata-management/document-cookie.html
  (4/5 -> 5/5, fully green): a cookie-averse document (one without a
  browsing context, e.g. createHTMLDocument) must read document.cookie
  as the empty string and silently ignore writes. Both accessors now
  no-op for documents that aren't a frame's active document.
- /html/dom/access-key-label.html (1/2 -> 2/2, fully green):
  HTMLElement.accessKeyLabel was missing. It reports an Alt+ chord for
  a valid single-character accesskey, like Chromium, and the empty
  string otherwise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Francis Bouvier
2026-07-12 12:13:16 +02:00
parent fb5bbf8e9a
commit 741a443d70
2 changed files with 28 additions and 2 deletions

View File

@@ -303,7 +303,18 @@ pub fn setDomain(self: *Document, value: []const u8) !void {
try doc_frame.js.setOrigin(key);
}
pub fn getCookie(_: *Document, frame: *Frame) ![]const u8 {
// A cookie-averse document (no browsing context: createHTMLDocument,
// DOMParser, XHR documents) reads cookies as the empty string and ignores
// writes.
fn isCookieAverse(self: *const Document, frame: *const Frame) bool {
const doc_frame = self._frame orelse return true;
return doc_frame.document != self and frame.document != self;
}
pub fn getCookie(self: *Document, frame: *Frame) ![]const u8 {
if (self.isCookieAverse(frame)) {
return "";
}
var buf: std.ArrayList(u8) = .empty;
try frame._session.cookie_jar.forRequest(frame.url, buf.writer(frame.local_arena), .{
.is_http = false,
@@ -312,7 +323,10 @@ pub fn getCookie(_: *Document, frame: *Frame) ![]const u8 {
return buf.items;
}
pub fn setCookie(_: *Document, cookie_str: []const u8, frame: *Frame) ![]const u8 {
pub fn setCookie(self: *Document, cookie_str: []const u8, frame: *Frame) ![]const u8 {
if (self.isCookieAverse(frame)) {
return cookie_str;
}
// we use the cookie jar's allocator to parse the cookie because it
// outlives the frame's arena.
const Cookie = @import("storage/Cookie.zig");

View File

@@ -372,6 +372,17 @@ pub fn setTranslate(self: *HtmlElement, translate: bool, frame: *Frame) !void {
try self.asElement().setAttributeSafe(comptime .wrap("translate"), .wrap(if (translate) "yes" else "no"), frame);
}
// accessKeyLabel: the UA-assigned shortcut for a valid (single character)
// accesskey, or the empty string. We report an Alt+ chord like Chromium.
pub fn getAccessKeyLabel(self: *HtmlElement, frame: *Frame) ![]const u8 {
const value = self.asElement().getAttributeSafe(comptime .wrap("accesskey")) orelse return "";
const codepoints = std.unicode.utf8CountCodepoints(value) catch return "";
if (codepoints != 1) {
return "";
}
return std.fmt.allocPrint(frame.call_arena, "Alt+{s}", .{value});
}
pub fn getPopover(self: *HtmlElement) ?[]const u8 {
const s = popover.getState(self.asElement()) orelse return null;
return @tagName(s);
@@ -1735,6 +1746,7 @@ pub const JsApi = struct {
pub const dir = bridge.accessor(HtmlElement.getDir, HtmlElement.setDir, .{ .ce_reactions = true });
pub const hidden = bridge.accessor(HtmlElement.getHidden, HtmlElement.setHidden, .{ .ce_reactions = true });
pub const translate = bridge.accessor(HtmlElement.getTranslate, HtmlElement.setTranslate, .{ .ce_reactions = true });
pub const accessKeyLabel = bridge.accessor(HtmlElement.getAccessKeyLabel, null, .{});
pub const popover = bridge.accessor(HtmlElement.getPopover, HtmlElement.setPopover, .{ .ce_reactions = true });
pub const showPopover = bridge.function(HtmlElement.showPopover, .{});
pub const hidePopover = bridge.function(HtmlElement.hidePopover, .{});