From aa051434cb8ce0c31576ebd16bec52549d7d390a Mon Sep 17 00:00:00 2001 From: egrs Date: Mon, 9 Mar 2026 08:14:41 +0100 Subject: [PATCH] add FontFace constructor and FontFaceSet.add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit headless stub for the FontFace API — constructor stores family/source, status is always "loaded", load() resolves immediately. enables sites that use new FontFace() for programmatic font loading (e.g. boursorama). --- src/browser/js/bridge.zig | 1 + src/browser/tests/css/font_face.html | 63 +++++++++++++++++ src/browser/webapi/css/FontFace.zig | 98 ++++++++++++++++++++++++++ src/browser/webapi/css/FontFaceSet.zig | 7 ++ 4 files changed, 169 insertions(+) create mode 100644 src/browser/tests/css/font_face.html create mode 100644 src/browser/webapi/css/FontFace.zig diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig index 2801f86b..fcbbea21 100644 --- a/src/browser/js/bridge.zig +++ b/src/browser/js/bridge.zig @@ -730,6 +730,7 @@ pub const JsApis = flattenTypes(&.{ @import("../webapi/css/CSSStyleRule.zig"), @import("../webapi/css/CSSStyleSheet.zig"), @import("../webapi/css/CSSStyleProperties.zig"), + @import("../webapi/css/FontFace.zig"), @import("../webapi/css/FontFaceSet.zig"), @import("../webapi/css/MediaQueryList.zig"), @import("../webapi/css/StyleSheetList.zig"), diff --git a/src/browser/tests/css/font_face.html b/src/browser/tests/css/font_face.html new file mode 100644 index 00000000..b515984b --- /dev/null +++ b/src/browser/tests/css/font_face.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/browser/webapi/css/FontFace.zig b/src/browser/webapi/css/FontFace.zig new file mode 100644 index 00000000..2196350f --- /dev/null +++ b/src/browser/webapi/css/FontFace.zig @@ -0,0 +1,98 @@ +const js = @import("../../js/js.zig"); +const Page = @import("../../Page.zig"); + +const FontFace = @This(); + +_family: []const u8, +_source: []const u8, +_style: []const u8, +_weight: []const u8, +_stretch: []const u8, +_unicode_range: []const u8, +_variant: []const u8, +_feature_settings: []const u8, +_display: []const u8, + +pub fn init(family: []const u8, source: []const u8, page: *Page) !*FontFace { + return page._factory.create(FontFace{ + ._family = try page.dupeString(family), + ._source = try page.dupeString(source), + ._style = "normal", + ._weight = "normal", + ._stretch = "normal", + ._unicode_range = "U+0-10FFFF", + ._variant = "normal", + ._feature_settings = "normal", + ._display = "auto", + }); +} + +pub fn getFamily(self: *const FontFace) []const u8 { + return self._family; +} + +pub fn getStyle(self: *const FontFace) []const u8 { + return self._style; +} + +pub fn getWeight(self: *const FontFace) []const u8 { + return self._weight; +} + +pub fn getStretch(self: *const FontFace) []const u8 { + return self._stretch; +} + +pub fn getUnicodeRange(self: *const FontFace) []const u8 { + return self._unicode_range; +} + +pub fn getVariant(self: *const FontFace) []const u8 { + return self._variant; +} + +pub fn getFeatureSettings(self: *const FontFace) []const u8 { + return self._feature_settings; +} + +pub fn getDisplay(self: *const FontFace) []const u8 { + return self._display; +} + +// load() - resolves immediately; headless browser has no real font loading. +pub fn load(_: *FontFace, page: *Page) !js.Promise { + return page.js.local.?.resolvePromise({}); +} + +// loaded - returns an already-resolved Promise. +pub fn getLoaded(_: *FontFace, page: *Page) !js.Promise { + return page.js.local.?.resolvePromise({}); +} + +pub const JsApi = struct { + pub const bridge = js.Bridge(FontFace); + + pub const Meta = struct { + pub const name = "FontFace"; + pub const prototype_chain = bridge.prototypeChain(); + pub var class_id: bridge.ClassId = undefined; + }; + + pub const constructor = bridge.constructor(FontFace.init, .{}); + pub const family = bridge.accessor(FontFace.getFamily, null, .{}); + pub const style = bridge.accessor(FontFace.getStyle, null, .{}); + pub const weight = bridge.accessor(FontFace.getWeight, null, .{}); + pub const stretch = bridge.accessor(FontFace.getStretch, null, .{}); + pub const unicodeRange = bridge.accessor(FontFace.getUnicodeRange, null, .{}); + pub const variant = bridge.accessor(FontFace.getVariant, null, .{}); + pub const featureSettings = bridge.accessor(FontFace.getFeatureSettings, null, .{}); + pub const display = bridge.accessor(FontFace.getDisplay, null, .{}); + pub const status = bridge.property("loaded", .{ .template = false, .readonly = true }); + pub const loaded = bridge.accessor(FontFace.getLoaded, null, .{}); + pub const load = bridge.function(FontFace.load, .{}); +}; + +const testing = @import("../../../testing.zig"); +test "WebApi: FontFace" { + try testing.htmlRunner("css/font_face.html", .{}); +} diff --git a/src/browser/webapi/css/FontFaceSet.zig b/src/browser/webapi/css/FontFaceSet.zig index 28703080..c91ebd58 100644 --- a/src/browser/webapi/css/FontFaceSet.zig +++ b/src/browser/webapi/css/FontFaceSet.zig @@ -1,6 +1,7 @@ const std = @import("std"); const js = @import("../../js/js.zig"); const Page = @import("../../Page.zig"); +const FontFace = @import("FontFace.zig"); const FontFaceSet = @This(); @@ -29,6 +30,11 @@ pub fn load(_: *FontFaceSet, font: []const u8, page: *Page) !js.Promise { return page.js.local.?.resolvePromise({}); } +// add(fontFace) - no-op; headless browser does not track loaded fonts. +pub fn add(self: *FontFaceSet, _: *FontFace) *FontFaceSet { + return self; +} + pub const JsApi = struct { pub const bridge = js.Bridge(FontFaceSet); @@ -43,6 +49,7 @@ pub const JsApi = struct { pub const ready = bridge.accessor(FontFaceSet.getReady, null, .{}); pub const check = bridge.function(FontFaceSet.check, .{}); pub const load = bridge.function(FontFaceSet.load, .{}); + pub const add = bridge.function(FontFaceSet.add, .{}); }; const testing = @import("../../../testing.zig");