Skip to content

Commit 8971cdd

Browse files
committed
Also return body and html elements
1 parent 3cdb062 commit 8971cdd

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
@@ -210,6 +210,9 @@ pub const HTMLDocument = struct {
210210
return "";
211211
}
212212

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

225+
// 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.
222226
pub fn _elementsFromPoint(_: *parser.DocumentHTML, x: f32, y: f32, state: *SessionState) ![]ElementUnion {
223227
const ix: i32 = @intFromFloat(@floor(x));
224228
const iy: i32 = @intFromFloat(@floor(y));
225229
const element = state.renderer.getElementAtPosition(ix, iy) orelse return &.{};
226230
// TODO if pointer-events set to none the underlying element should be returned (parser.documentGetDocumentElement(self.document);?)
227231

228-
// We need to return either 0 or 1 item, so we cannot fix the size to [1]*parser.Element
229-
// Converting the pointer to a slice []parser.Element is not supported by our framework.
230-
// So instead we just need to allocate the pointer to create a slice of 1.
231-
const heap_ptr = try state.call_arena.create(ElementUnion);
232-
heap_ptr.* = try Element.toInterface(element);
233-
return heap_ptr[0..1];
232+
var list = try std.ArrayList(ElementUnion).initCapacity(state.call_arena, 3);
233+
try list.append(try Element.toInterface(element));
234+
235+
// 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.
236+
// Thus we can add the HtmlHtmlElement and it's child HTMLBodyElement to the returned list.
237+
// TBD Should we instead return every parent that is an element? Note that a child does not physically need to be overlapping the parent.
238+
// Should we do a render pass on demand?
239+
const doc_elem = try parser.documentGetDocumentElement(parser.documentHTMLToDocument(state.document.?)) orelse {
240+
return list.items;
241+
};
242+
const body = try parser.documentHTMLBody(state.document.?) orelse {
243+
try list.append(try Element.toInterface(doc_elem));
244+
return list.items;
245+
};
246+
247+
try list.append(try Element.toInterface(parser.bodyToElement(body)));
248+
try list.append(try Element.toInterface(doc_elem));
249+
return list.items;
234250
}
235251
};
236252

@@ -287,7 +303,7 @@ test "Browser.HTML.Document" {
287303
}, .{});
288304

289305
try runner.testCases(&.{
290-
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Should these be document?
306+
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Return null since we only return element s when they have previously been localized
291307
.{ "document.elementsFromPoint(0.5, 0.5)", "" },
292308
.{
293309
\\ let div1 = document.createElement('div');
@@ -298,8 +314,10 @@ test "Browser.HTML.Document" {
298314
},
299315
.{ "document.elementFromPoint(0.5, 0.5)", "[object HTMLDivElement]" },
300316
.{ "let elems = document.elementsFromPoint(0.5, 0.5)", null },
301-
.{ "elems.length", "1" },
317+
.{ "elems.length", "3" },
302318
.{ "elems[0]", "[object HTMLDivElement]" },
319+
.{ "elems[1]", "[object HTMLBodyElement]" },
320+
.{ "elems[2]", "[object HTMLHtmlElement]" },
303321
}, .{});
304322

305323
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)