Hi Alex, On Tue, Apr 2, 2019, at 1:47 AM, Alex Henrie wrote: > Hi, I am trying to fix Bug 1529182,[1] but debugging the SVG <text> > code is particularly difficult for me because it uses at least six > coordinate spaces, and I can't figure out how they relate to each > other: > > - Run space > - Run user space > - Frame user space > - (Regular?) user space > - GFX space > - App space > > Can anyone here explain them to me?
Using this as an example: <!DOCTYPE html> <svg width="400" height="300"> <text x="100 200" y="100" style="font: 20px monospace">ab<tspan style="font-weight: bold">cd</tspan></text> </svg> the frame tree dump might look like this (with some unnecessary information elided): SVGOuterSVG(svg)(0) {0,0,24000,18000} SVGOuterSVGAnonChild(svg)(0) {0,0,0,0} SVGText(text)(1) {5985,4875,8190,1410} Block(text)(1) {0,0,2880,1440} line 7f2768ba20a8: count=2 {0,0,2880,1440} Text(0)"ab" {0,30,1440,1380} Inline(tspan)(1) {1440,30,1440,1380} Text(0)"cd" {0,0,1440,1380} The curly braces are the mRect values for each frame, which are in app units, which are 1/60 of a CSS pixel. SVGTextFrame works by leveraging the existing support for CSS rendering of blocks and inlines by building an nsBlockFrame for the <text> contents, nsInlineFrame for any <tspan>, and nsTextFrame for text nodes. This lets us avoid re-implementing text layout in the SVG code. Anything SVG specific, like text positioning attributes or <textPath>, are handled as a post-processing step when determining where to render each bit of the resulting CSS-positioned nsTextFrames. Generally these mRects are relative to their parent, but the nsBlockFrame child of the SVGTextFrame is used just to lay out the text and is not rendered directly, so its (0, 0) position doesn't mean much. Its width and height (2880 x 1440 app units) are the result of reflowing it without any constraints on its size. The layout of the block frame and its descendants is done independent of any SVG text positioning attributes and <textPath>. Because we leverage standard HTML/CSS rendering for SVG text, and because SVG text positioning attributes and <textPath>s can affect the positions (and rotations) of individual glyphs, we produce TextRenderedRun objects to represent each contiguous sequence of characters within an nsTextFrame that we can ask the text frame to render in one go. In this example, we end up producing three TextRenderedRuns: * One for "a", at SVG text position (100, 100). This covers {0,0,720,1380} of the first nsTextFrame. * One for "b", at SVG text position (200, 200). This covers {720,0,720,1380} of the first nsTextFrame. * One for "cd", at SVG text position (200 + advance_in_user_units("b"), 200). This corresponds to the entire {0,0,1440,1380} of the second nsTextFrame. Those rectangles might be in what you call "run space". I don't think they're really named in the code. In SVGTextFrame::PaintSVG, as we iterate over each TextRenderedRun, we need to set a transform on the gfxContext so that when asking an nsTextFrame to render some of its characters (the substring corresponding to the TextRenderedRun), it will appear in the right place. Most of the complication in SVGTextFrame.cpp is doing this. As for the coordinate systems you mention: User space is the local SVG coordinate system for an SVG element. In this example, the user space of the <text> element is the coordinate system the <svg> establishes, with (0, 0) at the top level of the <svg> element on the page, and (400, 300) at the bottom right. "Run user space" is a term I made up to mean a coordinate space that is the same as the <text>'s user space except translated so that the origin is at the top left of the rectangle that covers a given TextRenderedRun, and rotated by the TextRenderedRun's rotation. This example doesn't have any rotate="" attributes or <textPath>s, so there's no rotation here. So in this coordinate system, (0, 0) is at the top left of the "b" glyph cell, and (12, 23) is at the bottom right of the "b" glyph cell. TextRenderedRun::GetRunUserSpaceRect returns {0,0,12,23}, and TextRenderedRun::GetUserSpaceRect returns something like {200,86,12,23}, depending on the ascent/descent of the "b" (since the SVG text positioning aligns its alphabetic baseline at y=100). "Frame user space" is something that doesn't really correspond to what you see on the page. It's similar to "run user space": it's a coordinate system of the same scale as the <text>'s user space, but with its origin placed at the top left corner of an nsTextFrame's rectangle. For "b", TextRenderedRun::GetFrameUserSpaceRect returns {12,0,12,23} -- it's the same as GetRunUserSpaceRect but translated to where in its corresponding nsTextFrame is. I'm not sure about "GFX space" and "app space" as terms. There are many different units the coordinate values could be in -- see layout/base/Units.h. In SVG PaintSVG methods (e.g. SVGGeometryFrame::PaintSVG), setting `aTransform * aContext.CurrentMatrixDouble()` as the current matrix on the context will allow you to paint things in the current SVG element's user space. SVGTextFrame::PaintSVG doesn't use exactly that because it calls into nsTextFrame::PaintText, which doesn't expect to be in an SVG coordinate space. Please let me know if I can clarify anything else about the SVGTextFrame code. Thanks, Cameron _______________________________________________ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform