Skip to content

Commit 674743f

Browse files
committed
Also return body and html elements
1 parent 4cf7000 commit 674743f

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

src/browser/html/document.zig

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ pub const HTMLDocument = struct {
215215
return "";
216216
}
217217

218+
// Returns the topmost Element at the specified coordinates (relative to the viewport).
219+
// Since LightPanda requires the client to know what they are clicking on we do not return the underlying element at this moment
220+
// This can currenty only happen if the first pixel is click without having rendered any element. This will change when css properties are supported.
218221
// This returns an ElementUnion instead of a *Parser.Element in case the element somehow hasn't passed through the js runtime yet.
219222
pub fn _elementFromPoint(_: *parser.DocumentHTML, x: f32, y: f32, state: *SessionState) !?ElementUnion {
220223
const ix: i32 = @intFromFloat(@floor(x));
@@ -224,18 +227,31 @@ pub const HTMLDocument = struct {
224227
return try Element.toInterface(element);
225228
}
226229

230+
// Returns an array of all elements at the specified coordinates (relative to the viewport). The elements are ordered from the topmost to the bottommost box of the viewport.
227231
pub fn _elementsFromPoint(_: *parser.DocumentHTML, x: f32, y: f32, state: *SessionState) ![]ElementUnion {
228232
const ix: i32 = @intFromFloat(@floor(x));
229233
const iy: i32 = @intFromFloat(@floor(y));
230234
const element = state.renderer.getElementAtPosition(ix, iy) orelse return &.{};
231235
// TODO if pointer-events set to none the underlying element should be returned (parser.documentGetDocumentElement(self.document);?)
232236

233-
// We need to return either 0 or 1 item, so we cannot fix the size to [1]*parser.Element
234-
// Converting the pointer to a slice []parser.Element is not supported by our framework.
235-
// So instead we just need to allocate the pointer to create a slice of 1.
236-
const heap_ptr = try state.call_arena.create(ElementUnion);
237-
heap_ptr.* = try Element.toInterface(element);
238-
return heap_ptr[0..1];
237+
var list = try std.ArrayList(ElementUnion).initCapacity(state.call_arena, 3);
238+
try list.append(try Element.toInterface(element));
239+
240+
// Since we are using a flat renderer there is no hierarchy of elements. What we do know is that the element is part of the main document.
241+
// Thus we can add the HtmlHtmlElement and it's child HTMLBodyElement to the returned list.
242+
// TBD Should we instead return every parent that is an element? Note that a child does not physically need to be overlapping the parent.
243+
// Should we do a render pass on demand?
244+
const doc_elem = try parser.documentGetDocumentElement(parser.documentHTMLToDocument(state.document.?)) orelse {
245+
return list.items;
246+
};
247+
const body = try parser.documentHTMLBody(state.document.?) orelse {
248+
try list.append(try Element.toInterface(doc_elem));
249+
return list.items;
250+
};
251+
252+
try list.append(try Element.toInterface(parser.bodyToElement(body)));
253+
try list.append(try Element.toInterface(doc_elem));
254+
return list.items;
239255
}
240256
};
241257

@@ -292,7 +308,7 @@ test "Browser.HTML.Document" {
292308
}, .{});
293309

294310
try runner.testCases(&.{
295-
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Should these be document?
311+
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Return null since we only return element s when they have previously been localized
296312
.{ "document.elementsFromPoint(0.5, 0.5)", "" },
297313
.{
298314
\\ let div1 = document.createElement('div');
@@ -303,8 +319,10 @@ test "Browser.HTML.Document" {
303319
},
304320
.{ "document.elementFromPoint(0.5, 0.5)", "[object HTMLDivElement]" },
305321
.{ "let elems = document.elementsFromPoint(0.5, 0.5)", null },
306-
.{ "elems.length", "1" },
322+
.{ "elems.length", "3" },
307323
.{ "elems[0]", "[object HTMLDivElement]" },
324+
.{ "elems[1]", "[object HTMLBodyElement]" },
325+
.{ "elems[2]", "[object HTMLHtmlElement]" },
308326
}, .{});
309327

310328
try runner.testCases(&.{

src/browser/netsurf.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,6 +2261,10 @@ pub inline fn documentHTMLBody(doc_html: *DocumentHTML) !?*Body {
22612261
return @as(*Body, @ptrCast(body.?));
22622262
}
22632263

2264+
pub inline fn bodyToElement(body: *Body) *Element {
2265+
return @as(*Element, @ptrCast(body));
2266+
}
2267+
22642268
pub inline fn documentHTMLSetBody(doc_html: *DocumentHTML, elt: ?*ElementHTML) !void {
22652269
const err = documentHTMLVtable(doc_html).set_body.?(doc_html, elt);
22662270
try DOMErr(err);

0 commit comments

Comments
 (0)