Skip to content

Commit 8d892d2

Browse files
committed
Also return body and html elements
1 parent 39efb26 commit 8d892d2

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
@@ -228,6 +228,9 @@ pub const HTMLDocument = struct {
228228
return "";
229229
}
230230

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

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

246-
// We need to return either 0 or 1 item, so we cannot fix the size to [1]*parser.Element
247-
// Converting the pointer to a slice []parser.Element is not supported by our framework.
248-
// So instead we just need to allocate the pointer to create a slice of 1.
249-
const heap_ptr = try state.call_arena.create(ElementUnion);
250-
heap_ptr.* = try Element.toInterface(element);
251-
return heap_ptr[0..1];
250+
var list = try std.ArrayList(ElementUnion).initCapacity(state.call_arena, 3);
251+
try list.append(try Element.toInterface(element));
252+
253+
// 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.
254+
// Thus we can add the HtmlHtmlElement and it's child HTMLBodyElement to the returned list.
255+
// TBD Should we instead return every parent that is an element? Note that a child does not physically need to be overlapping the parent.
256+
// Should we do a render pass on demand?
257+
const doc_elem = try parser.documentGetDocumentElement(parser.documentHTMLToDocument(state.document.?)) orelse {
258+
return list.items;
259+
};
260+
const body = try parser.documentHTMLBody(state.document.?) orelse {
261+
try list.append(try Element.toInterface(doc_elem));
262+
return list.items;
263+
};
264+
265+
try list.append(try Element.toInterface(parser.bodyToElement(body)));
266+
try list.append(try Element.toInterface(doc_elem));
267+
return list.items;
252268
}
253269

254270
pub fn documentIsLoaded(html_doc: *parser.DocumentHTML, state: *SessionState) !void {
@@ -321,7 +337,7 @@ test "Browser.HTML.Document" {
321337
}, .{});
322338

323339
try runner.testCases(&.{
324-
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Should these be document?
340+
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Return null since we only return element s when they have previously been localized
325341
.{ "document.elementsFromPoint(0.5, 0.5)", "" },
326342
.{
327343
\\ let div1 = document.createElement('div');
@@ -332,8 +348,10 @@ test "Browser.HTML.Document" {
332348
},
333349
.{ "document.elementFromPoint(0.5, 0.5)", "[object HTMLDivElement]" },
334350
.{ "let elems = document.elementsFromPoint(0.5, 0.5)", null },
335-
.{ "elems.length", "1" },
351+
.{ "elems.length", "3" },
336352
.{ "elems[0]", "[object HTMLDivElement]" },
353+
.{ "elems[1]", "[object HTMLBodyElement]" },
354+
.{ "elems[2]", "[object HTMLHtmlElement]" },
337355
}, .{});
338356

339357
try runner.testCases(&.{

src/browser/netsurf.zig

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

2272+
pub inline fn bodyToElement(body: *Body) *Element {
2273+
return @as(*Element, @ptrCast(body));
2274+
}
2275+
22722276
pub inline fn documentHTMLSetBody(doc_html: *DocumentHTML, elt: ?*ElementHTML) !void {
22732277
const err = documentHTMLVtable(doc_html).set_body.?(doc_html, elt);
22742278
try DOMErr(err);

0 commit comments

Comments
 (0)