Skip to content

Commit 6b9dc90

Browse files
committed
Introduces an Env.String for persistent strings
If a webapi has a []const u8 parameter, then the page.call_arena is used. This is our favorite arena to use, but if the string value has a lifetime beyond the call, it then needs to be duped again (using page.arena). When a webapi has a Env.String parameter, the page.arena will be used directly to get the value from V8, removing the need for an intermediary dupe in the call_arena. This allows HTMLCollections to be streamlined. They no longer need to dupe the filter (tag name, class name, ...), which means they can no longer fail. It also means that we no longer need to needlessly dupe the string literals.
1 parent b7d26cf commit 6b9dc90

File tree

9 files changed

+126
-126
lines changed

9 files changed

+126
-126
lines changed

src/browser/dom/document.zig

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,22 +156,14 @@ pub const Document = struct {
156156
// the spec changed to return an HTMLCollection instead.
157157
// That's why we reimplemented getElementsByTagName by using an
158158
// HTMLCollection in zig here.
159-
pub fn _getElementsByTagName(
160-
self: *parser.Document,
161-
tag_name: []const u8,
162-
page: *Page,
163-
) !collection.HTMLCollection {
164-
return try collection.HTMLCollectionByTagName(page.arena, parser.documentToNode(self), tag_name, .{
159+
pub fn _getElementsByTagName(self: *parser.Document, tag_name: Env.String) !collection.HTMLCollection {
160+
return collection.HTMLCollectionByTagName(parser.documentToNode(self), tag_name.string, .{
165161
.include_root = true,
166162
});
167163
}
168164

169-
pub fn _getElementsByClassName(
170-
self: *parser.Document,
171-
classNames: []const u8,
172-
page: *Page,
173-
) !collection.HTMLCollection {
174-
return try collection.HTMLCollectionByClassName(page.arena, parser.documentToNode(self), classNames, .{
165+
pub fn _getElementsByClassName(self: *parser.Document, class_names: Env.String) !collection.HTMLCollection {
166+
return collection.HTMLCollectionByClassName(parser.documentToNode(self), class_names.string, .{
175167
.include_root = true,
176168
});
177169
}

src/browser/dom/element.zig

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
const std = @import("std");
2020

2121
const parser = @import("../netsurf.zig");
22+
const Env = @import("../env.zig").Env;
2223
const Page = @import("../page.zig").Page;
2324

2425
const css = @import("css.zig");
@@ -350,28 +351,18 @@ pub const Element = struct {
350351
return try parser.elementRemoveAttributeNode(self, attr);
351352
}
352353

353-
pub fn _getElementsByTagName(
354-
self: *parser.Element,
355-
tag_name: []const u8,
356-
page: *Page,
357-
) !collection.HTMLCollection {
358-
return try collection.HTMLCollectionByTagName(
359-
page.arena,
354+
pub fn _getElementsByTagName(self: *parser.Element, tag_name: Env.String) !collection.HTMLCollection {
355+
return collection.HTMLCollectionByTagName(
360356
parser.elementToNode(self),
361-
tag_name,
357+
tag_name.string,
362358
.{ .include_root = false },
363359
);
364360
}
365361

366-
pub fn _getElementsByClassName(
367-
self: *parser.Element,
368-
classNames: []const u8,
369-
page: *Page,
370-
) !collection.HTMLCollection {
362+
pub fn _getElementsByClassName(self: *parser.Element, class_names: Env.String) !collection.HTMLCollection {
371363
return try collection.HTMLCollectionByClassName(
372-
page.arena,
373364
parser.elementToNode(self),
374-
classNames,
365+
class_names.string,
375366
.{ .include_root = false },
376367
);
377368
}

src/browser/dom/html_collection.zig

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ pub const MatchByTagName = struct {
5252
tag: []const u8,
5353
is_wildcard: bool,
5454

55-
fn init(arena: Allocator, tag_name: []const u8) !MatchByTagName {
55+
fn init(tag_name: []const u8) MatchByTagName {
5656
if (std.mem.eql(u8, tag_name, "*")) {
5757
return .{ .tag = "*", .is_wildcard = true };
5858
}
5959

6060
return .{
61-
.tag = try arena.dupe(u8, tag_name),
61+
.tag = tag_name,
6262
.is_wildcard = false,
6363
};
6464
}
@@ -69,15 +69,14 @@ pub const MatchByTagName = struct {
6969
};
7070

7171
pub fn HTMLCollectionByTagName(
72-
arena: Allocator,
7372
root: ?*parser.Node,
7473
tag_name: []const u8,
7574
opts: Opts,
76-
) !HTMLCollection {
77-
return HTMLCollection{
75+
) HTMLCollection {
76+
return .{
7877
.root = root,
7978
.walker = .{ .walkerDepthFirst = .{} },
80-
.matcher = .{ .matchByTagName = try MatchByTagName.init(arena, tag_name) },
79+
.matcher = .{ .matchByTagName = MatchByTagName.init(tag_name) },
8180
.mutable = opts.mutable,
8281
.include_root = opts.include_root,
8382
};
@@ -86,9 +85,9 @@ pub fn HTMLCollectionByTagName(
8685
pub const MatchByClassName = struct {
8786
class_names: []const u8,
8887

89-
fn init(arena: Allocator, class_names: []const u8) !MatchByClassName {
88+
fn init(class_names: []const u8) !MatchByClassName {
9089
return .{
91-
.class_names = try arena.dupe(u8, class_names),
90+
.class_names = class_names,
9291
};
9392
}
9493

@@ -107,15 +106,14 @@ pub const MatchByClassName = struct {
107106
};
108107

109108
pub fn HTMLCollectionByClassName(
110-
arena: Allocator,
111109
root: ?*parser.Node,
112-
classNames: []const u8,
110+
class_names: []const u8,
113111
opts: Opts,
114112
) !HTMLCollection {
115113
return HTMLCollection{
116114
.root = root,
117115
.walker = .{ .walkerDepthFirst = .{} },
118-
.matcher = .{ .matchByClassName = try MatchByClassName.init(arena, classNames) },
116+
.matcher = .{ .matchByClassName = try MatchByClassName.init(class_names) },
119117
.mutable = opts.mutable,
120118
.include_root = opts.include_root,
121119
};
@@ -124,10 +122,8 @@ pub fn HTMLCollectionByClassName(
124122
pub const MatchByName = struct {
125123
name: []const u8,
126124

127-
fn init(arena: Allocator, name: []const u8) !MatchByName {
128-
return .{
129-
.name = try arena.dupe(u8, name),
130-
};
125+
fn init(name: []const u8) !MatchByName {
126+
return .{ .name = name };
131127
}
132128

133129
pub fn match(self: MatchByName, node: *parser.Node) !bool {
@@ -138,15 +134,14 @@ pub const MatchByName = struct {
138134
};
139135

140136
pub fn HTMLCollectionByName(
141-
arena: Allocator,
142137
root: ?*parser.Node,
143138
name: []const u8,
144139
opts: Opts,
145140
) !HTMLCollection {
146141
return HTMLCollection{
147142
.root = root,
148143
.walker = .{ .walkerDepthFirst = .{} },
149-
.matcher = .{ .matchByName = try MatchByName.init(arena, name) },
144+
.matcher = .{ .matchByName = try MatchByName.init(name) },
150145
.mutable = opts.mutable,
151146
.include_root = opts.include_root,
152147
};
@@ -203,8 +198,8 @@ pub fn HTMLCollectionChildren(
203198
};
204199
}
205200

206-
pub fn HTMLCollectionEmpty() !HTMLCollection {
207-
return HTMLCollection{
201+
pub fn HTMLCollectionEmpty() HTMLCollection {
202+
return .{
208203
.root = null,
209204
.walker = .{ .walkerNone = .{} },
210205
.matcher = .{ .matchFalse = .{} },
@@ -226,14 +221,11 @@ pub const MatchByLinks = struct {
226221
}
227222
};
228223

229-
pub fn HTMLCollectionByLinks(
230-
root: ?*parser.Node,
231-
opts: Opts,
232-
) !HTMLCollection {
233-
return HTMLCollection{
224+
pub fn HTMLCollectionByLinks(root: ?*parser.Node, opts: Opts) HTMLCollection {
225+
return .{
234226
.root = root,
235227
.walker = .{ .walkerDepthFirst = .{} },
236-
.matcher = .{ .matchByLinks = MatchByLinks{} },
228+
.matcher = .{ .matchByLinks = .{} },
237229
.mutable = opts.mutable,
238230
.include_root = opts.include_root,
239231
};
@@ -252,14 +244,11 @@ pub const MatchByAnchors = struct {
252244
}
253245
};
254246

255-
pub fn HTMLCollectionByAnchors(
256-
root: ?*parser.Node,
257-
opts: Opts,
258-
) !HTMLCollection {
259-
return HTMLCollection{
247+
pub fn HTMLCollectionByAnchors(root: ?*parser.Node, opts: Opts) HTMLCollection {
248+
return .{
260249
.root = root,
261250
.walker = .{ .walkerDepthFirst = .{} },
262-
.matcher = .{ .matchByAnchors = MatchByAnchors{} },
251+
.matcher = .{ .matchByAnchors = .{} },
263252
.mutable = opts.mutable,
264253
.include_root = opts.include_root,
265254
};

src/browser/dom/nodelist.zig

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818

1919
const std = @import("std");
20+
const Allocator = std.mem.Allocator;
2021

2122
const log = @import("../../log.zig");
2223
const parser = @import("../netsurf.zig");
@@ -101,13 +102,20 @@ pub const NodeList = struct {
101102

102103
nodes: NodesArrayList = .{},
103104

104-
pub fn deinit(self: *NodeList, alloc: std.mem.Allocator) void {
105-
// TODO unref all nodes
106-
self.nodes.deinit(alloc);
105+
pub fn deinit(self: *NodeList, allocator: Allocator) void {
106+
self.nodes.deinit(allocator);
107107
}
108108

109-
pub fn append(self: *NodeList, alloc: std.mem.Allocator, node: *parser.Node) !void {
110-
try self.nodes.append(alloc, node);
109+
pub fn ensureTotalCapacity(self: *NodeList, allocator: Allocator, n: usize) !void {
110+
return self.nodes.ensureTotalCapacity(allocator, n);
111+
}
112+
113+
pub fn append(self: *NodeList, allocator: Allocator, node: *parser.Node) !void {
114+
try self.nodes.append(allocator, node);
115+
}
116+
117+
pub fn appendAssumeCapacity(self: *NodeList, node: *parser.Node) void {
118+
self.nodes.appendAssumeCapacity(node);
111119
}
112120

113121
pub fn get_length(self: *const NodeList) u32 {

src/browser/dom/performance.zig

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub const Performance = struct {
6161
return milliTimestamp() - self.time_origin;
6262
}
6363

64-
pub fn _mark(_: *Performance, name: []const u8, _options: ?PerformanceMark.Options, page: *Page) !PerformanceMark {
64+
pub fn _mark(_: *Performance, name: Env.String, _options: ?PerformanceMark.Options, page: *Page) !PerformanceMark {
6565
const mark: PerformanceMark = try .constructor(name, _options, page);
6666
// TODO: Should store this in an entries list
6767
return mark;
@@ -155,7 +155,7 @@ pub const PerformanceMark = struct {
155155
startTime: ?f64 = null,
156156
};
157157

158-
pub fn constructor(name: []const u8, _options: ?Options, page: *Page) !PerformanceMark {
158+
pub fn constructor(name: Env.String, _options: ?Options, page: *Page) !PerformanceMark {
159159
const perf = &page.window.performance;
160160

161161
const options = _options orelse Options{};
@@ -166,9 +166,7 @@ pub const PerformanceMark = struct {
166166
}
167167

168168
const detail = if (options.detail) |d| try d.persist() else null;
169-
170-
const duped_name = try page.arena.dupe(u8, name);
171-
const proto = PerformanceEntry{ .name = duped_name, .entry_type = .mark, .start_time = start_time };
169+
const proto = PerformanceEntry{ .name = name.string, .entry_type = .mark, .start_time = start_time };
172170

173171
return .{ .proto = proto, .detail = detail };
174172
}

src/browser/html/document.zig

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,67 +115,69 @@ pub const HTMLDocument = struct {
115115
}
116116

117117
pub fn _getElementsByName(self: *parser.DocumentHTML, name: []const u8, page: *Page) !NodeList {
118-
const arena = page.arena;
119118
var list: NodeList = .{};
120119

121-
if (name.len == 0) return list;
120+
if (name.len == 0) {
121+
return list;
122+
}
122123

123124
const root = parser.documentHTMLToNode(self);
124-
var c = try collection.HTMLCollectionByName(arena, root, name, .{
125+
var c = try collection.HTMLCollectionByName(root, name, .{
125126
.include_root = false,
126127
});
127128

128129
const ln = try c.get_length();
130+
try list.ensureTotalCapacity(page.arena, ln);
131+
129132
var i: u32 = 0;
130-
while (i < ln) {
133+
while (i < ln) : (i += 1) {
131134
const n = try c.item(i) orelse break;
132-
try list.append(arena, n);
133-
i += 1;
135+
list.appendAssumeCapacity(n);
134136
}
135137

136138
return list;
137139
}
138140

139-
pub fn get_images(self: *parser.DocumentHTML, page: *Page) !collection.HTMLCollection {
140-
return try collection.HTMLCollectionByTagName(page.arena, parser.documentHTMLToNode(self), "img", .{
141+
pub fn get_images(self: *parser.DocumentHTML) collection.HTMLCollection {
142+
return collection.HTMLCollectionByTagName(parser.documentHTMLToNode(self), "img", .{
141143
.include_root = false,
142144
});
143145
}
144146

145-
pub fn get_embeds(self: *parser.DocumentHTML, page: *Page) !collection.HTMLCollection {
146-
return try collection.HTMLCollectionByTagName(page.arena, parser.documentHTMLToNode(self), "embed", .{
147+
pub fn get_embeds(self: *parser.DocumentHTML) collection.HTMLCollection {
148+
return collection.HTMLCollectionByTagName(parser.documentHTMLToNode(self), "embed", .{
147149
.include_root = false,
148150
});
149151
}
150152

151-
pub fn get_plugins(self: *parser.DocumentHTML, page: *Page) !collection.HTMLCollection {
152-
return get_embeds(self, page);
153+
pub fn get_plugins(self: *parser.DocumentHTML) collection.HTMLCollection {
154+
return get_embeds(self);
153155
}
154156

155-
pub fn get_forms(self: *parser.DocumentHTML, page: *Page) !collection.HTMLCollection {
156-
return try collection.HTMLCollectionByTagName(page.arena, parser.documentHTMLToNode(self), "form", .{
157+
pub fn get_forms(self: *parser.DocumentHTML) collection.HTMLCollection {
158+
return collection.HTMLCollectionByTagName(parser.documentHTMLToNode(self), "form", .{
157159
.include_root = false,
158160
});
159161
}
160162

161-
pub fn get_scripts(self: *parser.DocumentHTML, page: *Page) !collection.HTMLCollection {
162-
return try collection.HTMLCollectionByTagName(page.arena, parser.documentHTMLToNode(self), "script", .{
163+
pub fn get_scripts(self: *parser.DocumentHTML) collection.HTMLCollection {
164+
return collection.HTMLCollectionByTagName(parser.documentHTMLToNode(self), "script", .{
163165
.include_root = false,
164166
});
165167
}
166168

167-
pub fn get_applets(_: *parser.DocumentHTML) !collection.HTMLCollection {
168-
return try collection.HTMLCollectionEmpty();
169+
pub fn get_applets(_: *parser.DocumentHTML) collection.HTMLCollection {
170+
return collection.HTMLCollectionEmpty();
169171
}
170172

171-
pub fn get_links(self: *parser.DocumentHTML) !collection.HTMLCollection {
172-
return try collection.HTMLCollectionByLinks(parser.documentHTMLToNode(self), .{
173+
pub fn get_links(self: *parser.DocumentHTML) collection.HTMLCollection {
174+
return collection.HTMLCollectionByLinks(parser.documentHTMLToNode(self), .{
173175
.include_root = false,
174176
});
175177
}
176178

177-
pub fn get_anchors(self: *parser.DocumentHTML) !collection.HTMLCollection {
178-
return try collection.HTMLCollectionByAnchors(parser.documentHTMLToNode(self), .{
179+
pub fn get_anchors(self: *parser.DocumentHTML) collection.HTMLCollection {
180+
return collection.HTMLCollectionByAnchors(parser.documentHTMLToNode(self), .{
179181
.include_root = false,
180182
});
181183
}

src/browser/html/window.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,10 @@ pub const Window = struct {
246246
return self.createTimeout(cbk, 0, page, .{ .name = "queueMicrotask" });
247247
}
248248

249-
pub fn _matchMedia(_: *const Window, media: []const u8, page: *Page) !MediaQueryList {
249+
pub fn _matchMedia(_: *const Window, media: Env.String) !MediaQueryList {
250250
return .{
251251
.matches = false, // TODO?
252-
.media = try page.arena.dupe(u8, media),
252+
.media = media.string,
253253
};
254254
}
255255

0 commit comments

Comments
 (0)