Yoga: A cross-platform layout engine
code.facebook.com
code.facebook.com
This library looks very useful for those who use React Native or want a layout engine in C# or Java for their mobile app, but as someone who works in an industry (bio/chem engineering) who develops applications around tools in that industry and thinking that Facebook may one day enter that field, or even if we create a software patent for some idea we create while developing the tools, it makes me uneasy whenever a new Facebook open source project, especially one with the potential to become popular in a specific area of software development, is introduced.
Also, another thing to keep in mind is not every big company does this with their open source tech. For example, Angular and Visual Studio Code are both under MIT license.
In the case you describe, what it boils down to is yeah, if your business intends to sue Facebook for patent infringement, you probably shouldn't be dependent on any of Facebook's IP or patents for your business. There are lots of things companies do to discourage other companies from suing them. Giving out free software is one of the nicer ways a company can choose to go about it.
If you sue a company with competent lawyers, their defensive patent portfolio will be unleashed on you to the greatest extent possible, whether you intentionally infringed or not. If you use technology similar to Angular and sued Google, you'd be in a similar position. Facebook's patent grants simply codify this, and so they've taken the blame for something that was always hanging over every developer's head with any patented software anywhere.
https://en.wikipedia.org/wiki/Software_patents_and_free_soft...
Well, there's some argument that including a patent license makes the other license less likely to be construed as implicitly extending to patents, even if it says "additional". But you really shouldn't be depending on either the MIT or BSD license counting as a patent license.
See also: https://writing.kemitchell.com/2016/09/21/MIT-License-Line-b...
Edit: I misremembered the scope of the Apache 2 patent license, sorry.
There are other companies (I would be betraying confidences to list who) that have looked at it and decided not to use it because of the strong retaliation clause. I should elaborate that those companies are not planning to sue FB as far as I know, but they want to preserve the opportunity to do so (i.e. they don't want to de-weaponize their patent portfolio with respect to FB).
In effect, it's more, not less, permissive and honest. INAL, but that's what I've been told by one.
[0] https://github.com/facebook/react/wiki/Sites-Using-React
I have seen tooling that analyzes licenses, but not for node or client-side javascript. Maybe I'm just in the dark.
To answer your original question, I found this statement by Automattic's legal counsel[0]:
> “Automattic looked at the legal issues with Facebook’s patent license on React,” Sieminski said. “The termination provisions of the patent license aren’t ideal, but are not a blocker to using React as part of Calypso.”
[0] https://wptavern.com/automattic-will-continue-to-use-react-j...
A library might have a stronger community or better documentation than the other. They might be equivalent today but evolve differently in the future. Etc.
The choice between two libraries is never that easy.
I assume your company is not developing UX patents and the concern is more around developing a suite of products that use a FB library and dealing with unexpected costs or restrictions?
I would hate to avoid using what I thought were the most productive tools in anticipation of a very unlikely event. You'd essentially be paying a productivity penalty now, to try and avoid a productivity penalty in the future if you have to rewrite something.
The odds of a company like yours in a vertical getting sued by Facebook I would guess are vanishingly small.
Now if your core IP competes directly with FB I can see a little more risk because they could plausibly have strategic reasons to make your life difficult as well as a potential damages claim. However this would be a special case for only certain companies to worry about.
Do you have a patent that Facebook might infringe on?
The license granted hereunder will terminate, automatically and without notice, if you (or any of your subsidiaries, corporate affiliates or agents) initiate directly or indirectly, or take a direct financial interest in, any Patent Assertion: (i) against Facebook or any of its subsidiaries or corporate affiliates, (ii) against any party if such Patent Assertion arises in whole or in part from any software, technology, product or service of Facebook or any of its subsidiaries or corporate affiliates, or (iii) against any party relating to the Software. Notwithstanding the foregoing, if Facebook or any of its subsidiaries or corporate affiliates files a lawsuit alleging patent infringement against you in the first instance, and you respond by filing a patent infringement counterclaim in that lawsuit against that party that is unrelated to the Software, the license granted hereunder will not terminate under section (i) of this paragraph due to such counterclaim.
Also, your link doesn't actually dispel any fears I have. It specifically doesn't mention about if I sue Facebook for patent infringement if I have a valid patent that Facebook infringes upon, which is the main basis of my argument and worry.
That seems like a pretty reasonable stance for distributing an open source project.
If you counter-sue FB after they have initiated a patent suit against you, you are ok, as long as your counter-suit does not cover patents you were licensed via using React, Yoga, etc.
This type of patent language is called a "strong patent retaliation clause." What you are describing also exists (Apache uses it) and is called the "weak patent retaliation clause." They are not the same.
The license granted hereunder will terminate, automatically and without notice, if you (or any of your subsidiaries, corporate affiliates or agents) initiate directly or indirectly, or take a direct financial interest in, any Patent Assertion: (i) against Facebook or any of its subsidiaries or corporate affiliates
At that point, I am infringing any patents that FB have on all of {React/Yoga/etc}. Thus opening myself up immediately to a counter-patent suit, even I infringe no other FB patents.
tl;dr any patent suit initiated by me (troll or legitimate), revokes all the patent grants for every FB product using this license.
The API is similar to Yoga. I hadn't seen Yoga before, and I'm surprised at how similar it is. It seems like Yoga is about the same age (or older?) than my Layout library.
It's meant to be easily embedded into existing software, such as game engines, OpenGL-based tools, custom GUI libraries, etc. without requiring its own complicated build system. Its API and layout engine seems to work in a way similar to Yoga, but it doesn't have pre-made bindings for any existing GUI toolkits. There is, however, an example binding for the Lua scripting language.
API comparison:
Yoga:
YGNodeRef root = YGNodeNew();
YGNodeStyleSetWidth(root, 500);
YGNodeStyleSetHeight(root, 120);
YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
YGNodeRef image = YGNodeNew();
YGNodeStyleSetWidth(image, 80);
YGNodeStyleSetMargin(image, YGEdgeEnd, 20);
YGNodeInsertChild(root, image, 0);
Layout: lay_context ctx;
lay_init_context(&ctx);
lay_id root = lay_item(&ctx);
lay_set_size_xy(&ctx, root, 500, 120);
lay_set_contain(&ctx, root, LAY_ROW);
lay_id image = lay_item(&ctx);
lay_set_size_xy(&ctx, image, 80, 0);
lay_set_margins_ltrb(&ctx, image, 0, 0, 20, 0);
lay_insert(&ctx, root, image);
The Layout library can handle laying out tens of thousands of items in a few microseconds, so I would expect Yoga to have similar performance. (Layout is meant to work stutter-free and waste-free with layouts that could be animated or changing every frame in a game engine.)One major difference I noticed, though, is that Yoga seems to allocate for each individual node, whereas Layout uses a single resizable contiguous buffer. This is gives it pretty good CPU cache performance (writes are all in their own separate region of the buffer) and allows you to do complete rebuilds of the layout hierarchy without any heap allocations. It's nice if you have a dynamic layout and want to keep the layout calculations fast/cheap. It might be interesting to do benchmarks of the two libraries in different scenarios.
Are there any other libraries similar to Yoga and Layout?
I'm curious though, will this be eventually ported to JavaScript? Yeah yeah I know "flexbox is already on the web!" but if you could write a layout in this fashion versus using style sheets then you could take it and directly apply it to any of your applications (even if you have to convert between languages the exact same setup is still there it's just a straight up conversion).
Overall cool idea and implementation. Curious to see where it goes from here.
It has been ported already.
https://www.npmjs.com/package/css-layout
Oddly enough there's no git repository. Only the npm package has the pure JS code. And the last release was from last year. Fortunately it looks it was easy to port, if one needs a more recent version.
css-layout is the original project, it was written in JS and then automatically translated into Java & co. It had some bugs, and Facebook rewrote the thing directly to a native implementation but decided to drop JS as they were not using that variation internally. This is a shame as I love CSS-layout for calculating tween points in layout animations on the web. FB said at this point they have no plans for an official JS port of the new version aka yoga.
[0]: https://kentor.me/posts/creating-diagrams-with-react-svg-and...
Ok, you have a layout engine. For what widgets? Windows.Forms? WPF? Xamarin Forms? Can those even use a third party layout engine?
I'm slightly confused :)
One thought I had is that one could use this layout engine to do the calculations for the positioning of visual objects on the screen, but you would have to essentially build a fully integrated layout manager that renders to the particular framework you're using. Maybe overridding the hooks for existing layout managers that come with the particular UI framework (for example, WPF has layout managers).
For example, in WinForms, if you build the UI programmatically rather than old fashioned drag-and-drop, you could set X/Y positions, widths/sizes etc. per the constraints generated by this engine. Needs to be observable/reactive so the UI changes are fed back into the engine and then the UI automatically changes - much like existing layout manager tech.
Perhaps doing this work/exercise was left to the open source community/reader. There aren't any examples/tests showing how to integrate this layout manager with any existing .NET UI widget frameworks. It looks like they wrote the integration with .NET in C# (on MacOS as well), and tested the layout engine itself, but that's about it.
EDIT: Possible hooks for old WinForms maybe? https://msdn.microsoft.com/en-us/library/z9w7ek2f(v=vs.110)....
"We have a script which to launch C# test on macOS, csharp/tests/Facebook.Yoga/test_macos.sh."
Here's a similar but seemingly dead project:
It's already cross-platform; cross-language would probably be a little much to ask :)
I'm not sure I follow; it's supported in multiple languages already. Am I missing something?
Say, I build a declarative tree describing a layout, and I render it. Now I remove one item from the tree. Can the layout engine efficiently remove the item from the view, and... (now it comes) provide an animation for it? As in, the item slowly losing opacity, then the surrounding items moving closer together? (Or a different animation depending on settings).
Of course, the opposite should also be possible (i.e., inserting an item).
Implement this, and we're a step beyond CSS, because so far this has not been possible (elegantly) in CSS. I.e., remove the element from the DOM tree, and it is gone immediately (without the animation). And no amount of CSS can fix this.
We have LayoutAnimation inside of React Native which lets you do that. It's not very well documented and the delete method is not implemented, but the idea is there :)
https://facebook.github.io/react-native/docs/layoutanimation...
[0]: https://facebook.github.io/yoga/http://github.com/facebook/y...
It seems ... smallish, which was a pleasant surprise. The core Yoga/ folder contains six files which is certainly fewer than I expected.
Didn't have time to do a full read-through, but one thing that I couldn't ignore is the use of a pointer-hiding typedef for the core layout node:
typedef struct YGNode *YGNodeRef;
I'm really opposed to "hiding the asterisk" in C, since whether or not a thing is a pointer typically matters, and code becomes harder to read when you need to think about this more.Even stranger, though, is that then most function protypes look like this:
void YGNodeMarkDirty(const YGNodeRef node);
So, you have a function called "mark" which really sounds like a mutating, modifying, operation. But it's declared to take a constant node reference!Peeking at the code, what it does boils down to:
if (!node->isDirty) {
node->isDirty = true;
...
}
So it really is modifying, there's no trickery involved (like having node be a handle or indirect reference). It then recurses upwards through the chain of parent nodes, like you'd expect.This works since the "const" here doesn't apply to the pointed-at object (it's distinct from the un-typedef:ed version "const struct YGNode * node"), it applies to the reference.
So the code jumps through these hoops and adds a const to the external interface, which doesn't matter, all it does is say "yeah, this function won't re-assign the reference variable to point at something else". Which, in my opinion, is not very useful information, as opposed to "this function doesn't write to the object you pass in" which you'd get with the non-asterisked version.
Can anyone shed some light on why one would do this?
Additionally, I'm a bit skeptical about the use of C here: this stuff tends to end up exposed to the user and security-sensitive.
[1]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.207...
That said, I think the more likely conclusion for security vulnerabilities is the one you allude to, where people will probably end up reusing this component elsewhere and exposing the engine to potentially hostile input somewhere along the line, and it might not end well.
They say it has bindings for Android and yea, I can generate these Yoga objects in Java but how exactly would I integrate this with my Android view hierarchy? Do I need to use React for that? The documentation says exactly nothing about this.
What's the piece of information that I'm missing?
Flexbox could be implemented as a framework on top of this.
I too like constraint-based layout, but I have to admit flexbox is nice in that it has very predictable behavior. The main hangup I have with flexbox is that it doesn't allow for layout based on aspect ratios, but Yoga has extensions that resolve this issue.
I think that pg's point #2 from this post applies
http://paulgraham.com/popular.html
"It is a mistake to try to baby the user with long-winded expressions that are meant to resemble English. Cobol is notorious for this flaw. A hacker would consider being asked to write."
I've spend a few months playing with Cassowary before working on css-layout and had long chats with its creator Greg Badros and the people behind https://gridstylesheets.org/.
Cassowary underlying abstraction is a linear inequation solver. So you give it a bunch of constraints of the form ax + by + cz + d < 0 and it's going to give you values for x, y and z.
## There are two innovations in Cassowary:
1) There's a concept of strength (required, strong, medium, weak) which allows you to define which rules should be dropped in case of conflicts. This is a very different way to think about building UI and was a really fun exercise.
That said, I had to build a dedicated tool to show me which rules where overridden or why otherwise it was very hard to understand what happened when the layout didn't work as I expected.
2) Cassowary is an iterative solver, this means that it's not going to recompute the entire simplex from scratch on every tiny update.
## The biggest issue with Cassowary is that you cannot express everything with a linear system of equations:
The most annoying instance is line breaking. You cannot encode how lines are going to break as a set of linear inequations. In practice, what happens is that you're going to "fake it" by iterating outside of the simplex by first giving it a rough size and then do another pass with the real one. It usually works but you are not guaranteed for it to converge nor to have the optimal layout.
## In practice
It's extremely painful to write all the inequations yourself. If you want to have a container with an item of height 100px with 5px of padding it looks like.
obj.left = parent.left + 5
obj.top = parent.top + 5
obj.right = parent.right - 5
obj.height = 100
parent.height = obj + 5
For every single object you need to define 4 inequations to "define": top, left, width and height which is very verbose.So I started writing abstractions for containers, padding... At some point, I realized that I was just reimplementing flexbox. But it was a worst implementation of flexbox because it didn't properly work with text and was way slower.
The other difficulty is that you need references to all those elements. In order to tell where an element is, you need a reference to your parent. This model doesn't work well with React components where you only shouldn't know about your parent.
## Where it shines
The places where constraint solver shines is when you have a wysiwyg element builder. You have a reference to all the elements as they are visible on-screen so it's very easy to link them and you can show 4 inputs for each constraint.
This is very useful for xcode interface builder and would be a good fit for designer tools like photoshop.
Hopefully this gives some light around why we didn't proceed with cassowary :)
You had a really inspiring use of fuzz testing and TDD. You used a hilarious technique to implement it in several languages at once. And I heard a rumor you did it all over your paternity leave?!
That sounds like "strength" was probably the wrong approach. Why not require the developer to simply resolve conflicts? Your set of inequalities are a basic type system and you tried to resolve your type errors by layering some secondary weird "overriding" type system over top. Better to just resolve the errors from the get-go, and when it compiles, you know it will run correctly.
> The most annoying instance is line breaking. You cannot encode how lines are going to break as a set of linear inequations.
Is this discussed anywhere in more detail? It doesn't sound right to me, unless I'm misunderstanding what you mean here.
2) The height of a text is not a linear function based on the width of the container. You can't say, the height of the text is 10px * number of characters * width of the container.
Instead, if you add a single more character that makes it go to the next line it's going to add a single lineheight.
So, you can't encode this inside of the simplex and you need to do it as a separate pass.
It sounds like a limited set of discontinuous functions are needed, like how media queries are used in CSS. The constraints to satisfy are defined by a set of top-level discontinuous functions on environmental parameters, but the set is always fixed so it's pretty simple to detect when you need to switch to a different set of constraints. Wouldn't that suffice?
> The height of a text is not a linear function based on the width of the container. You can't say, the height of the text is 10px * number of characters * width of the container.
For simplicity, let's take the easiest case of a fixed width font and we'll hard wrap at X characters, regardless of whitespace positions. The number of lines L and the height of the text H in px is then given by:
L = char_px_width * char_count / container_px_per_line
H = L * char_px_height
Agreed? If so, then that case isn't difficult, but difficulties arise when you want better wrapping behaviour based on whitespace with a non-fixed width font. I agree that doing it precisely with linear equations doesn't seem feasible, but it seems like we can closely approximate it to minimize the reflows needed to converge on the final result.Suppose we set char_px_height=the widest character of the typeface (ditto for char_px_height) so we overestimate the dimensions needed. A quick google search suggests that the average word length for ordinary English is around 5 characters. So with avg_word_length=5, the above equation changes to something like:
L = char_px_width * avg_word_length * ceiling(char_count / avg_word_length) / container_px_per_line
This should miss the actual number of lines needed at most by 1, except when dealing with highly irregular text. Then again, the avg_word_length can be constantly adjusted on the fly based on the reflows you have to do, so this should quickly converge too. Does this sound right?Edit: sorry, that last calculation is obviously wrong, I was rushing out the door. The idea is to estimate number of lines from the average nnumber of words that would fit per line.
I have been using it for some time and it is an huge step in the right direction.
A downside of Yoga seems to be its tooling, ConstraintLayout is very well integrated with Android Studio. Actually they created it hand in hand with a rewrite of its layout editor.
Actually, CL one of the reasons behind the creation of RL is to improve on RL : - remove the need to nest for complex layouts. Nesting has some intrinsic measure/layout overhead. CL solves this by allowing way more types of relative constraint. The only remaining reasons for manual ViewGroups are performances (still faster than any generalistic approach) or really deep customization.
- solve some of RL qwirks. There are a couple of behaviors which are surprising. CL streamline these corner cases.
- deeper layouting possibilities
- integrated with a better layout editor. By better, I mean something you might choose to use, unlike the previous layout editor.
CL is in beta right now, you can add it as an external lib (that way the android team can update it anytime they want). The layout itself is already useable in production, the layout editor is where there are still some potential bugs.
The previous layout editor was pretty much unusable. Even though XML is ugly it is still efficient to work with (especially since the IDE auto completes all the cruft), so almost nobody was using the old layout editor.
The new one is still in beta and has some rough edges but it sounds like this will actually be useable and maybe even faster than editing the XML in some cases.
Does that mean that Yoga is too low level to be used directly by application developers? Who's the intended audience?
GitHub - https://github.com/facebook/yoga
Flexbox and the explicit inheritance used in react native makes styling so much nicer.
Hardware laptop vs software library?
- One layout concept across different platforms. This allows developers to more easily collaborate and jump between platforms and re-use knowledge.
- Decouple layout from rendering. A lot of UI frameworks couple layout tightly with rendering which often ties the layout to be run on the main thread. By decoupling layout we are able to run it asynchronously. https://code.facebook.com/posts/531104390396423/components-f... Talks about how we make use of this.
...I'm not sure that you'd actually want to, but that's a different issue.
It seems confusing to me to have "layout" as a separate component rather than having it be tightly integrated with the rest of the UI framework.
Which is a shame, since the lack of aspect ratio support is one of Flexbox's failings (and apparently resolved with Yoga)
And is it light on dependencies?
This is becoming a serious issue with many different things. Try to search for info about the visual studio "Code" editor for example.
Facts and common sense are not fashionable in this age though unfortunately as evidenced by your (current) low vote on your comment.
Also:
It's not a "fact" that such names are a bad choice. It's an opinion. Personally I prefer evocative names, and that requires – almost by definition – to reuse words already in use.
It's also not "fashionable" or "trendy". To quote Aristoteles: "The young people today are rotten to the core, or they would have never named this software 'R'".
The alternative is the pharmaceutical naming system which includes a review to ensure that names are not just unique, but unlikely to confuse even with bad handwriting. The result is an endless stream of forgettable, but pronounceable, UUIDs with too many 'Z's.
(... and "Plan B", which is probably my favorite example of evocative naming).
I think now we can start on CSS => Compiled Style Sheets. :)
Or hip, depending on where you are :)
It is equivalent of naming a sports team Rednecks.
Is it fair to generalize like this across all the members of HN? You might argue that this is the case for those that down-voted, but everyone?