I believe int tx, int ty -- which we see sprinkled around the rendering tree -- are the offset from the top left corner of the current renderer's parent to the containing block. Is that correct? In SVG we use IntSize containingBlockOffset in the rare places we have to deal with this RenderBoxModelObject-only concept. I've long considered fixing renders to use IntPoint and IntSize instead of x, y, tx, ty, but to do that, I need to make sure I understand what tx, ty are, and what name they should have as an IntSize. -eric
On Aug 23, 2010, at 12:51 AM, Eric Seidel wrote:
I believe int tx, int ty -- which we see sprinkled around the rendering tree -- are the offset from the top left corner of the current renderer's parent to the containing block. Is that correct?
In SVG we use IntSize containingBlockOffset in the rare places we have to deal with this RenderBoxModelObject-only concept.
I've long considered fixing renders to use IntPoint and IntSize instead of x, y, tx, ty, but to do that, I need to make sure I understand what tx, ty are, and what name they should have as an IntSize.
I think it would be good to use IntPoint and IntSize in more places in the render tree. My understanding of tx/ty is imperfect so you may want to have a rendering guru weigh in, but I believe it works like this: - x(), y() are a renderer's position in the coordinate system of its parent - tx, ty are the origin of the parent's coordinate system relative to the origin for its layer. When a layer paints, it establishes a CTM such that its own origin is 0, 0 (I think). When a renderer paints, the first thing it does is add its own x() and y() to tx and ty, and it passes the new values of tx and ty to its children. There's two ways to express this in size/point terms. First, some rules for Point / Size math: - You can add a Size to a Point to get a new Point. - You can add a Size to a Size to get a new Size. - It doesn't make logical sense to add two Points, so the operation doesn't exist. Points are absolute and Sizes are relative; you can't add two absolutes. The more obvious way, given the variable names, would be to make x(), y() an IntPoint, with a name like originInParentCoordinates() (hopefully less verbose, but you get the idea). tx, ty could be named parentOffsetFromLayerCoordinates or something. This seems to be the intent of the names - that x,y is a point and tx, ty is a translation. But this doesn't work in point/size logic. You repeatedly add x(), y() to tx, ty to get a new tx, ty. But that means you're adding a point to a size and expecting to get a new size - but that's not how it works. The way that works is to reverse the logic. tx, ty becomes IntPoint parentOrigin. x(), y() becomes IntSize offsetFromParent(). You add your offsetFromParent() to your parentOrigin to get the parentOrigin you pass from your children. This reverses the idea of which is the point and which is the offset, but it fits the axioms of point/size arithmetic and I believe it is ultimately more logical. You can see this in part from the shorter names. The first line in a ::paint() method would be IntPoint origin = parentOrigin + offsetFromParent(). How sweet is that? (Note: I omitted many details here, such as accounting for scroll offsets. Renderers that are scrolled account for the scroll offset in the tx, ty they pass their children even though this is not strictly their *own* origin.) BTW I have rewritten parts of render tree logic before to use IntPoint, IntSize, and point/size operations instead of dealing with individual coordinates, and I always found the code far more readable. This is particularly so when I stopped to figure out what should be a size and what should be a point based on the axioms of point/size arithmetic. Regards, Maciej
On Aug 23, 2010, at 4:33 AM, Maciej Stachowiak wrote:
- tx, ty are the origin of the parent's coordinate system relative to the origin for its layer. When a layer paints, it establishes a CTM such that its own origin is 0, 0 (I think).
They are relative to a painting root, which will basically either be the document or a compositing layer.
The more obvious way, given the variable names, would be to make x(), y() an IntPoint, with a name like originInParentCoordinates()
It already is an IntPoint internally. There's already a method to access it as a point. IntPoint location() const
(hopefully less verbose, but you get the idea). tx, ty could be named parentOffsetFromLayerCoordinates or something. This seems to be the intent of the names - that x,y is a point and tx, ty is a translation. But this doesn't work in point/size logic. You repeatedly add x(), y() to tx, ty to get a new tx, ty. But that means you're adding a point to a size and expecting to get a new size - but that's not how it works.
I think a helper method that does the right thing solves this problem (rather than having to flip what x/y and tx/ty mean just to do some math operation). dave
On Aug 23, 2010, at 12:11 PM, David Hyatt wrote:
(hopefully less verbose, but you get the idea). tx, ty could be named parentOffsetFromLayerCoordinates or something. This seems to be the intent of the names - that x,y is a point and tx, ty is a translation. But this doesn't work in point/size logic. You repeatedly add x(), y() to tx, ty to get a new tx, ty. But that means you're adding a point to a size and expecting to get a new size - but that's not how it works.
I think a helper method that does the right thing solves this problem (rather than having to flip what x/y and tx/ty mean just to do some math operation).
dave
Just to clarify, if tx/ty turned into an IntSize offset, I think you could just add a helper method like .asOffset() to IntPoint to solve this particular problem. Instead of tx += x(); ty += y(); You could write: offset += location().asOffset(); I'd also have no objection to just building that right into RenderBox... offset += locationOffset(); dave (hyatt@apple.com)
On Aug 23, 2010, at 10:20 AM, David Hyatt wrote:
On Aug 23, 2010, at 12:11 PM, David Hyatt wrote:
(hopefully less verbose, but you get the idea). tx, ty could be named parentOffsetFromLayerCoordinates or something. This seems to be the intent of the names - that x,y is a point and tx, ty is a translation. But this doesn't work in point/size logic. You repeatedly add x(), y() to tx, ty to get a new tx, ty. But that means you're adding a point to a size and expecting to get a new size - but that's not how it works.
I think a helper method that does the right thing solves this problem (rather than having to flip what x/y and tx/ty mean just to do some math operation).
dave
Just to clarify, if tx/ty turned into an IntSize offset, I think you could just add a helper method like .asOffset() to IntPoint to solve this particular problem.
Instead of
tx += x(); ty += y();
You could write:
offset += location().asOffset();
I'd also have no objection to just building that right into RenderBox...
offset += locationOffset();
I think the current code is wrong in thinking of tx/ty as an offset instead of a point. Once the local offset is added, they are passed directly to painting methods. The first place I looked at, RenderBoxModelObject::paintBoxShadow, starts with: IntRect rect(tx, ty, w, h); Then it does some rect math before passing a rect based on this to the GraphicsContext. I couldn't find any place where tx, ty are actually used in an obviously offset-like way. As another data point, several places make an IntPoint from tx, ty, none make an IntSize. You usually list the location first, not the offset, when adding coordinates. They get treated as a point pretty much all over the place. If we converted all that code to using IntPoint/IntSize, and tx/ty got replaced with an IntSize, we'd constantly have to convert it to an IntPoint to actually do any painting. If you constantly have to convert it to a point, it should just be a point. By contrast, x()/y() are fairly often used as an IntSize (sometimes they are even passed to the IntSize constructor), though they also get used in a point-like way in other code. To some extent it's arbitrary what you consider a point and what you consider an offset. A point is just an offset from the origin, for some defined origin. In painting code, it's convenient for the points to be in the CTM space, since that is what you need whenever you get down to a GraphicsContext call. Regards, Maciej
On Aug 23, 2010, at 12:51 AM, Eric Seidel wrote:
I believe int tx, int ty -- which we see sprinkled around the rendering tree -- are the offset from the top left corner of the current renderer's parent to the containing block. Is that correct?
In SVG we use IntSize containingBlockOffset in the rare places we have to deal with this RenderBoxModelObject-only concept.
I've long considered fixing renders to use IntPoint and IntSize instead of x, y, tx, ty, but to do that, I need to make sure I understand what tx, ty are, and what name they should have as an IntSize.
tx, ty are a painting offset which starts as 0,0 at the current painting root, and are then accumulated as you go down. The painting root may be the root renderer, or it may be a compositing layer, or something painting with a 2D transform. It would be possible to have block renderers change the coordinate system to their local coordinates when painting to eliminate tx, ty for blocks, but you'd still have to do something for inlines, and there may be other non-simple cases too. Simon
participants (4)
-
David Hyatt
-
Eric Seidel
-
Maciej Stachowiak
-
Simon Fraser