mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-14 15:03:27 -04:00
Merge pull request #3370 from lightpanda-io/svg-ctm
webapi: SVGGraphicsElement.getCTM and getScreenCTM
This commit is contained in:
2 files changed
+75
No files matched your search
@@ -210,3 +210,29 @@
|
||||
testing.expectEqual(true, rootBox.height >= 100);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=ctm>
|
||||
{
|
||||
const circle = document.querySelector('#transformed > g > circle');
|
||||
const m = circle.getCTM();
|
||||
testing.expectEqual(true, m instanceof DOMMatrix);
|
||||
testing.expectEqual(2, m.a);
|
||||
testing.expectEqual(0, m.b);
|
||||
testing.expectEqual(0, m.c);
|
||||
testing.expectEqual(2, m.d);
|
||||
testing.expectEqual(10, m.e);
|
||||
testing.expectEqual(20, m.f);
|
||||
|
||||
const root = $('#root').getCTM();
|
||||
testing.expectEqual(1, root.a);
|
||||
testing.expectEqual(0, root.e);
|
||||
|
||||
const rect = $('#root').getBoundingClientRect();
|
||||
const s = circle.getScreenCTM();
|
||||
testing.expectEqual(2, s.a);
|
||||
testing.expectEqual(rect.x + 10, s.e);
|
||||
testing.expectEqual(rect.y + 20, s.f);
|
||||
|
||||
testing.expectEqual(null, document.createElementNS('http://www.w3.org/2000/svg', 'rect').getCTM());
|
||||
}
|
||||
</script>
|
||||
@@ -25,6 +25,7 @@ const Node = @import("../../Node.zig");
|
||||
const Element = @import("../../Element.zig");
|
||||
const Factory = @import("../../../Factory.zig");
|
||||
const DOMRect = @import("../../DOMRect.zig");
|
||||
const DOMMatrix = @import("../../DOMMatrix.zig");
|
||||
const DOMMatrixReadOnly = @import("../../DOMMatrixReadOnly.zig");
|
||||
const SvgElement = @import("../Svg.zig");
|
||||
const AnimatedTransformList = @import("../../svg/AnimatedTransformList.zig");
|
||||
@@ -128,6 +129,8 @@ pub const JsApi = struct {
|
||||
pub const requiredExtensions = bridge.accessor(Graphics.getRequiredExtensions, null, .{});
|
||||
pub const systemLanguage = bridge.accessor(Graphics.getSystemLanguage, null, .{});
|
||||
pub const getBBox = bridge.function(Graphics.getBBox, .{});
|
||||
pub const getCTM = bridge.function(Graphics.getCTM, .{});
|
||||
pub const getScreenCTM = bridge.function(Graphics.getScreenCTM, .{});
|
||||
};
|
||||
|
||||
// SVGBoundingBoxOptions is not modelled: Chrome declares no parameter at all
|
||||
@@ -218,6 +221,52 @@ fn accumulateChildren(parent: *Graphics, matrix: PathData.Matrix, bounds: *PathD
|
||||
}
|
||||
}
|
||||
|
||||
/// Composes `transform` attributes from the element up to, excluding, its
|
||||
/// nearest <svg>. Null when the element isn't in a document.
|
||||
pub fn getCTM(self: *Graphics, frame: *Frame) !?*DOMMatrix {
|
||||
return currentTransformMatrix(self, .viewport, frame);
|
||||
}
|
||||
|
||||
/// Like getCTM through every enclosing <svg>, offset by where the outermost
|
||||
/// one sits on the page. Nested viewport x/y are not applied.
|
||||
pub fn getScreenCTM(self: *Graphics, frame: *Frame) !?*DOMMatrix {
|
||||
return currentTransformMatrix(self, .screen, frame);
|
||||
}
|
||||
|
||||
fn currentTransformMatrix(self: *Graphics, space: enum { viewport, screen }, frame: *Frame) !?*DOMMatrix {
|
||||
if (!self.asNode().isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matrix = transformMatrix(self.asElement());
|
||||
var outermost: ?*Element = if (self._type == .svg) self.asElement() else null;
|
||||
var node = self.asNode().parentNode();
|
||||
while (node) |n| : (node = n.parentNode()) {
|
||||
const element = n.is(Element) orelse break;
|
||||
if (element._namespace != .svg) break;
|
||||
const graphics = element.as(SvgElement).is(Graphics) orelse continue;
|
||||
if (graphics._type == .svg) {
|
||||
if (space == .viewport) break;
|
||||
outermost = element;
|
||||
}
|
||||
matrix = transformMatrix(element).multiply(matrix);
|
||||
}
|
||||
|
||||
if (space == .screen) {
|
||||
if (outermost) |svg| {
|
||||
const rect = svg.boundingClientRectValues(frame);
|
||||
matrix = (PathData.Matrix{ .e = rect.x, .f = rect.y }).multiply(matrix);
|
||||
}
|
||||
}
|
||||
|
||||
return try DOMMatrix.create(.{
|
||||
matrix.a, matrix.b, 0, 0,
|
||||
matrix.c, matrix.d, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
matrix.e, matrix.f, 0, 1,
|
||||
}, true, frame._page);
|
||||
}
|
||||
|
||||
fn transformMatrix(element: *Element) PathData.Matrix {
|
||||
const raw = element.getAttributeSafe(comptime .wrap("transform")) orelse return .{};
|
||||
const trimmed = std.mem.trim(u8, raw, " \t\r\n");
|
||||
|
||||
Reference in new issue
Block a user