facebook / yoga

Yoga is an embeddable layout engine targeting web standards.

Home Page:https://yogalayout.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Why can't we round node width/height directly in roundLayoutResultsToPixelGrid()?

kennethpu opened this issue · comments

Report

In PixelGrid.roundLayoutResultsToPixelGrid() it appears that we are calculating a node's rounded width/height as follows:

  1. Calculate the start position of the node.
const double absoluteNodeLeft = absoluteLeft + nodeLeft;
  1. Using the start position and computed width, calculate the end position of the node.
const double absoluteNodeRight = absoluteNodeLeft + nodeWidth;
  1. Calculate rounded node width/height as the difference between the rounded start/end positions of the node.
node->setLayoutDimension(
    roundValueToPixelGrid(
        absoluteNodeRight, 
        pointScaleFactor, 
        (textRounding && hasFractionalWidth), 
        (textRounding && !hasFractionalWidth)
    ) -
    roundValueToPixelGrid(
        absoluteNodeLeft, 
        pointScaleFactor, 
        false, 
        textRounding
     ),
     Dimension::Width);

It's not clear to me why we need to calculate rounded width/height in this way as opposed to rounding the width/height values directly, and it also seems like this may introduce rounding errors as noted in this previously opened issue (#901). Curious if the proposed solution on that issue has merit or if there are other issues not being considered.

As an iOS developer utilizing a fork of Yoga (really appreciate this project btw!) I'm also curious if you foresee any issues with tweaking the rounding logic on our fork to more closely mirror Apple's strategy of rounding down origin values and rounding up size values to the nearest pixel boundary. Are there other parts of the layout algorithm we would need to update for consistency?

I would love to change how layout rounding works in terms of how it's executed, but haven't put a lot of thought into it's underlying rounding logic. We have seen real bugs from it.

A goal of this style of rounding is to not introduce "gaps", so it makes sense for the start position reference to be the previous rounded pixel I think.

The text rounding flag can on the other hand introduce overlaps, which is also wrong.

Yoga's algorithm is indeed quite clever in it's avoidance of gaps in the resultant layout. The commit that introduced the current rounding mode to Yoga (aa5b296) has an excellent writeup on the motivation. I believe Apple's strategy will result in 1px overlaps in some cases, which is perhaps not so bad (this definitely seems to me like a problem where there isn't really one best solution) but is something to bear in mind.

Regarding your having a fork of Yoga, are there also other changes that you have made locally? And would you be interested in upstreaming those?