From e91da78ebb77b63a6ba09edcdec7ccb45c31efd3 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Mon, 9 Mar 2026 16:08:17 +0800 Subject: [PATCH] Optimize FontFace Follow up to https://github.com/lightpanda-io/browser/pull/1743 Allow eager cleanup with finalizer. User properties for (what are currently) constants. --- src/browser/webapi/css/FontFace.zig | 100 ++++++++++++------------- src/browser/webapi/css/FontFaceSet.zig | 38 +++++++++- 2 files changed, 81 insertions(+), 57 deletions(-) diff --git a/src/browser/webapi/css/FontFace.zig b/src/browser/webapi/css/FontFace.zig index 2196350f..0da560fc 100644 --- a/src/browser/webapi/css/FontFace.zig +++ b/src/browser/webapi/css/FontFace.zig @@ -1,64 +1,54 @@ +// Copyright (C) 2023-2026 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + +const std = @import("std"); const js = @import("../../js/js.zig"); const Page = @import("../../Page.zig"); +const Allocator = std.mem.Allocator; + const FontFace = @This(); +_arena: Allocator, _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", - }); + _ = source; + + const arena = try page.getArena(.{.debug = "FontFace"}); + errdefer page.releaseArena(arena); + + const self = try arena.create(FontFace); + self.* = .{ + ._arena = arena, + ._family = try arena.dupe(u8, family), + }; + return self; +} + +pub fn deinit(self: *FontFace, _: bool, page: *Page) void { + page.releaseArena(self._arena); } 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({}); @@ -76,18 +66,20 @@ pub const JsApi = struct { pub const name = "FontFace"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const weak = true; + pub const finalizer = bridge.finalizer(FontFace.deinit); }; 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 style = bridge.property("normal", .{ .template = false, .readonly = true }); + pub const weight = bridge.property("normal", .{ .template = false, .readonly = true }); + pub const stretch = bridge.property("normal", .{ .template = false, .readonly = true }); + pub const unicodeRange = bridge.property("U+0-10FFFF", .{ .template = false, .readonly = true }); + pub const variant = bridge.property("normal", .{ .template = false, .readonly = true }); + pub const featureSettings = bridge.property("normal", .{ .template = false, .readonly = true }); + pub const display = bridge.property("auto", .{ .template = false, .readonly = true }); pub const loaded = bridge.accessor(FontFace.getLoaded, null, .{}); pub const load = bridge.function(FontFace.load, .{}); }; diff --git a/src/browser/webapi/css/FontFaceSet.zig b/src/browser/webapi/css/FontFaceSet.zig index c91ebd58..12f090bd 100644 --- a/src/browser/webapi/css/FontFaceSet.zig +++ b/src/browser/webapi/css/FontFaceSet.zig @@ -1,15 +1,45 @@ +// Copyright (C) 2023-2026 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + const std = @import("std"); const js = @import("../../js/js.zig"); const Page = @import("../../Page.zig"); const FontFace = @import("FontFace.zig"); +const Allocator = std.mem.Allocator; + const FontFaceSet = @This(); -// Padding to avoid zero-size struct, which causes identity_map pointer collisions. -_pad: bool = false, +_arena: Allocator, pub fn init(page: *Page) !*FontFaceSet { - return page._factory.create(FontFaceSet{}); + const arena = try page.getArena(.{.debug = "FontFaceSet"}); + errdefer page.releaseArena(arena); + + const self = try arena.create(FontFaceSet); + self.* = .{ + ._arena = arena, + }; + return self; +} + +pub fn deinit(self: *FontFaceSet, _: bool, page: *Page) void { + page.releaseArena(self._arena); } // FontFaceSet.ready - returns an already-resolved Promise. @@ -42,6 +72,8 @@ pub const JsApi = struct { pub const name = "FontFaceSet"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const weak = true; + pub const finalizer = bridge.finalizer(FontFaceSet.deinit); }; pub const size = bridge.property(0, .{ .template = false, .readonly = true });