mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 08:18:59 +00:00
preserve casing (tags/attributes) for SVG/XML/MathML namespace
This commit is contained in:
@@ -355,7 +355,7 @@ pub fn documentIsLoaded(self: *Page) void {
|
||||
}
|
||||
|
||||
pub fn _documentIsLoaded(self: *Page) !void {
|
||||
const event = try Event.init("DOMContentLoaded", .{}, self);
|
||||
const event = try Event.init("DOMContentLoaded", .{ .bubbles = true }, self);
|
||||
try self._event_manager.dispatch(
|
||||
self.document.asEventTarget(),
|
||||
event,
|
||||
@@ -1292,7 +1292,9 @@ fn populateElementAttributes(self: *Page, element: *Element, list: anytype) !voi
|
||||
var existing = list orelse return;
|
||||
|
||||
var attributes = try self.arena.create(Element.Attribute.List);
|
||||
attributes.* = .{};
|
||||
attributes.* = .{
|
||||
.normalize = existing.normalize,
|
||||
};
|
||||
|
||||
var it = existing.iterator();
|
||||
while (it.next()) |attr| {
|
||||
@@ -1306,12 +1308,10 @@ fn populateElementAttributes(self: *Page, element: *Element, list: anytype) !voi
|
||||
if (@TypeOf(list) == @TypeOf(null) or list.count() == 0) {
|
||||
return;
|
||||
}
|
||||
var attributes = try self.arena.create(Element.Attribute.List);
|
||||
attributes.* = .{};
|
||||
var attributes = try element.createAttributeList(self);
|
||||
while (list.next()) |attr| {
|
||||
try attributes.putNew(attr.name.local.slice(), attr.value.slice(), self);
|
||||
}
|
||||
element._attributes = attributes;
|
||||
}
|
||||
|
||||
pub fn createTextNode(self: *Page, text: []const u8) !*Node {
|
||||
|
||||
@@ -242,13 +242,7 @@ fn _addAttrsIfMissingCallback(self: *Parser, node: *Node, attributes: h5e.Attrib
|
||||
const element = node.as(Element);
|
||||
const page = self.page;
|
||||
|
||||
const attr_list = element._attributes orelse blk: {
|
||||
const a = try page.arena.create(@import("../webapi/element/Attribute.zig").List);
|
||||
a.* = .{};
|
||||
element._attributes = a;
|
||||
break :blk a;
|
||||
};
|
||||
|
||||
const attr_list = try element.getOrCreateAttributeList(page);
|
||||
while (attributes.next()) |attr| {
|
||||
const name = attr.name.local.slice();
|
||||
const value = attr.value.slice();
|
||||
|
||||
@@ -52,3 +52,16 @@
|
||||
testing.expectEqual(0, ec.length);
|
||||
testing.expectEqual(undefined, ec[0]);
|
||||
</script>
|
||||
|
||||
<script id=nonBreakingSpace>
|
||||
// Test non-breaking space encoding (critical for React hydration)
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = 'hello\xa0world';
|
||||
testing.expectEqual('hello\xa0world', div.textContent);
|
||||
testing.expectEqual('hello world', div.innerHTML);
|
||||
|
||||
// Test that outerHTML also encodes non-breaking spaces correctly
|
||||
const p = document.createElement('p');
|
||||
p.textContent = 'XAnge\xa0Privacy';
|
||||
testing.expectEqual('<p>XAnge Privacy</p>', p.outerHTML);
|
||||
</script>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<SVG id=svg3></SVG>
|
||||
|
||||
<script id=svg>
|
||||
{
|
||||
let svg1 = $('#svg1');
|
||||
testing.expectEqual('svg', svg1.tagName);
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', svg1.namespaceURI);
|
||||
@@ -25,4 +26,41 @@
|
||||
const svg5 = document.createElement('SvG');
|
||||
testing.expectEqual('SVG', svg5.tagName);
|
||||
testing.expectEqual('http://www.w3.org/1999/xhtml', svg5.namespaceURI);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svg id=lower width="200" height="100" style="border:1px solid #ccc" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
|
||||
<rect></rect>
|
||||
<text x="100" y="95" font-size="14" text-anchor="middle">OVER 9000!!</text>
|
||||
</svg>
|
||||
|
||||
<SVG ID=UPPER WIDTH="200" HEIGHT="100" STYLE="BORDER:1PX SOLID #CCC" XMLNS="http://www.w3.org/2000/svg" VIEWBOX="0 0 200 100">
|
||||
<RECT></RECT>
|
||||
<TEXT X="100" Y="95" FONT-SIZE="14" TEXT-ANCHOR="MIDDLE">OVER 9000!!!</TEXT>
|
||||
</SVG>
|
||||
|
||||
<script id=casing>
|
||||
testing.expectEqual(false, 'AString' instanceof SVGElement);
|
||||
|
||||
const lower = $('#lower');
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', lower.getAttribute('xmlns'));
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', lower.getAttributeNode('xmlns').value);
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', lower.attributes.getNamedItem('xmlns').value);
|
||||
testing.expectEqual('0 0 200 100', lower.getAttribute('viewBox'));
|
||||
testing.expectEqual('viewBox', lower.getAttributeNode('viewBox').name);
|
||||
testing.expectEqual(true, lower.outerHTML.includes('viewBox'));
|
||||
testing.expectEqual('svg', lower.tagName);
|
||||
testing.expectEqual('rect', lower.querySelector('rect').tagName);
|
||||
testing.expectEqual('text', lower.querySelector('text').tagName);
|
||||
|
||||
const upper = $('#UPPER');
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', upper.getAttribute('xmlns'));
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', upper.getAttributeNode('xmlns').value);
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', upper.attributes.getNamedItem('xmlns').value);
|
||||
testing.expectEqual('0 0 200 100', upper.getAttribute('viewBox'));
|
||||
testing.expectEqual('viewBox', upper.getAttributeNode('viewBox').name);
|
||||
testing.expectEqual(true, upper.outerHTML.includes('viewBox'));
|
||||
testing.expectEqual('svg', upper.tagName);
|
||||
testing.expectEqual('rect', upper.querySelector('rect').tagName);
|
||||
testing.expectEqual('text', upper.querySelector('text').tagName);
|
||||
</script>
|
||||
|
||||
@@ -28,3 +28,22 @@
|
||||
testing.expectEqual('a<p></p>b', container.innerHTML);
|
||||
testing.expectEqual(3, container.childNodes.length);
|
||||
</script>
|
||||
|
||||
<span id=token class="token" style="color:#ce9178">"puppeteer "</span>
|
||||
<h3 id=name>Leto
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
Atreides</h3>
|
||||
<script id=adjascent_test_nodes>
|
||||
const token = $('#token');
|
||||
testing.expectEqual('"puppeteer "', token.firstChild.nodeValue);
|
||||
|
||||
const name = $('#name');
|
||||
testing.expectEqual([
|
||||
"Leto\n ",
|
||||
" ",
|
||||
"\n ",
|
||||
" ",
|
||||
"\n Atreides"
|
||||
], Array.from(name.childNodes).map((n) => n.nodeValue));
|
||||
</script>
|
||||
|
||||
@@ -118,6 +118,7 @@ pub const JsApi = struct {
|
||||
// in our Entry? Because that would require an extra 8 bytes for every single
|
||||
// attribute in the DOM, and, again, we expect that to almost always be null.
|
||||
pub const List = struct {
|
||||
normalize: bool,
|
||||
_list: std.DoublyLinkedList = .{},
|
||||
|
||||
pub fn isEmpty(self: *const List) bool {
|
||||
@@ -273,7 +274,9 @@ pub const List = struct {
|
||||
entry: ?*Entry,
|
||||
};
|
||||
fn getEntryAndNormalizedName(self: *const List, name: []const u8, page: *Page) !NormalizeAndEntry {
|
||||
const normalized = try normalizeNameForLookup(name, page);
|
||||
const normalized =
|
||||
if (self.normalize) try normalizeNameForLookup(name, page) else name;
|
||||
|
||||
return .{
|
||||
.normalized = normalized,
|
||||
.entry = self.getEntryWithNormalizedName(normalized),
|
||||
|
||||
Reference in New Issue
Block a user