<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:"Yu Gothic";
panose-1:2 11 4 0 0 0 0 0 0 0;}
@font-face
{font-family:Aptos;
panose-1:2 11 0 4 2 2 2 2 2 4;}
@font-face
{font-family:"Iosevka Fixed SS16";
panose-1:2 0 5 9 3 0 0 0 0 4;}
@font-face
{font-family:"Times New Roman \(Body CS\)";
panose-1:2 11 6 4 2 2 2 2 2 4;}
@font-face
{font-family:"\@Yu Gothic";
panose-1:2 11 4 0 0 0 0 0 0 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:10.0pt;
font-family:"Aptos",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Iosevka Fixed SS16";
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;
mso-ligatures:none;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style>
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Thank you, this explanation (
<a href="https://bugs.openjdk.org/browse/JDK-8354801?focusedId=14770935&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14770935">
https://bugs.openjdk.org/browse/JDK-8354801?focusedId=14770935&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14770935</a> ) makes a lot of sense.<br>
<br>
What happens when the Parent decides it does need to change its bounds after all as a result of requestLayoutChildren()? Wouldn't this necessitate requestLayout()/requestParentLayout() so we end up with multiple pulses and resulting flicker?<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span style="font-size:12.0pt;color:black">From:
</span></b><span style="font-size:12.0pt;color:black">John Hendrikx <john.hendrikx@gmail.com><br>
<b>Date: </b>Wednesday, April 16, 2025 at 16:13<br>
<b>To: </b>Nir Lisker <nlisker@gmail.com>, Andy Goryachev <andy.goryachev@oracle.com><br>
<b>Cc: </b>openjfx-dev@openjdk.org <openjfx-dev@openjdk.org><br>
<b>Subject: </b>[External] : Re: Unnecessary layouts; TLDR; new method "requestLocalLayout"<o:p></o:p></span></p>
</div>
<p>I tested this with several controls that were triggering layouts (like on cursor movements), and I saw no adverse effects. Basically, any time you interact with a control and it triggers a full layout but its bounds didn't change (ie. nothing in the UI
changed position or size) the full layout was unnecessary.<o:p></o:p></p>
<p>Most Skins/Controls do the simple thing of registering listeners on any properties that may change their appearance and calling requestLayout, while calling requestLayout should really be reserved for things that change their computeMin/Pref/Max values.
If there were no changes in any of those, then the parent layout won't have changes either (and so on) so the final layout result will be the exact same as before, yet tens of thousands of calculations will have been done. Because of how say HBox calculates
its size, it also queries any siblings, which in turn may be containers...<o:p></o:p></p>
<p>The only things "stopping" layout propagation are things like scroll panes. This is why TextArea is a lot less likely to trigger a layout all the way to the root vs TextField.<o:p></o:p></p>
<p>--John<o:p></o:p></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On 16/04/2025 17:04, Nir Lisker wrote:<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Sounds good. Have you tried a prototype implementation for a built-in JavaFX control/Pane, just to see how well it works?<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On Wed, Apr 16, 2025 at 5:50</span><span style="font-size:12.0pt;font-family:"Arial",sans-serif"> </span><span style="font-size:12.0pt">PM Andy Goryachev <<a href="mailto:andy.goryachev@oracle.com">andy.goryachev@oracle.com</a>>
wrote:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">This might be a good idea from an API perspective, but please be careful - this optimization might break the behavior.
For instance, the scroll bar might change as a result of a key event in the TextArea, so the text layout is still needed, however expensive.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">(and I like Michael's suggestion of naming the method requestLayoutChildren())</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
<div id="m_-1880730255040356136mail-editor-reference-message-container">
<div>
<div>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="mso-margin-top-alt:auto;margin-bottom:12.0pt"><b><span style="font-size:12.0pt;color:black">From:
</span></b><span style="font-size:12.0pt;color:black">openjfx-dev <<a href="mailto:openjfx-dev-retn@openjdk.org" target="_blank">openjfx-dev-retn@openjdk.org</a>> on behalf of John Hendrikx <<a href="mailto:john.hendrikx@gmail.com" target="_blank">john.hendrikx@gmail.com</a>><br>
<b>Date: </b>Monday, April 14, 2025 at 08:56<br>
<b>To: </b><a href="mailto:openjfx-dev@openjdk.org" target="_blank">openjfx-dev@openjdk.org</a> <<a href="mailto:openjfx-dev@openjdk.org" target="_blank">openjfx-dev@openjdk.org</a>><br>
<b>Subject: </b>Unnecessary layouts; TLDR; new method "requestLocalLayout"</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:auto;margin-bottom:12.0pt"><span style="font-size:11.0pt">I've been writing a container that does layout, and I've been using it<br>
extensively in my latest project.<br>
<br>
I noticed that many skins and controls will call requestLayout(), not<br>
realizing that this will mark the current node + all parent nodes with<br>
`NEEDS_LAYOUT`. This causes all those containers to call `compute`<br>
methods and execute their `layoutChildren`, even though your control may<br>
only have changed something that does NOT change its layout bounds (like<br>
a color, background, alignment or even things like a cursor shape or<br>
position). These computations are expensive, involving querying of all<br>
children of each container to find out their min/pref/max sizes, do<br>
content bias calculations, splitting space over each control and many<br>
many snapXYZ calls -- all leading to no visual layout change...<br>
<br>
For example, a TextArea or TextField will call requestLayout on every<br>
character typed, every cursor movement, and every text content change. <br>
None of those affects their bounds (at least, in my experience, these<br>
controls are not continuously resizing themselves when I scroll or type<br>
things...). TextField will even change its cursor shape every time its<br>
value is updated, even if that value is simply bound to a Slider and the<br>
field doesn't have focus at all -- this field will then trigger layout<br>
on itself and all its ancestors even if it is in a completely unrelated<br>
area of the UI (not close to the slider).<br>
<br>
It seems that in many cases these controls and skins just want their<br>
layoutChildren method to be called, as their main layout logic is<br>
located there -- duplicating this logic partially for every minor<br>
property change that doesn't affect its bounds is error prone, so I can<br>
completely follow this reasoning. However, using requestLayout to get<br>
layoutChildren called is very expensive.<br>
<br>
There is a better way: call setNeedsLayout(true) -- this is a protected<br>
method that any Node has access to, and basically will only call<br>
layoutChildren on your own Node. It marks all the parent nodes as<br>
`DIRTY_BRANCH`, which means that on a layout pass it will traverse down<br>
to see which nodes actually needs layout (it won't call layoutChildren<br>
for each ancestor, which is a big win).<br>
<br>
Because of its protected nature (and its required parameter which must<br>
be true), it is a bit hard to use. I'm thinking it might be a good idea<br>
to introduce a new method here, a request layout call that schedules a<br>
Node for layout without forcing all ancestors to do the same. This way<br>
Skin and Control designers can clearly see the two options and choose<br>
what is required:<br>
<br>
requestLayout -- my bounds likely have changed (font change,<br>
border/padding change, spacing change), so please call compute methods<br>
and redo the entire layout<br>
<br>
requestLocalLayout -- my bounds have not changed (color changes,<br>
background changes, content changes within a ScrollPane, cursor changes,<br>
cursor position changes, alignment changes)<br>
<br>
What do you think?<br>
<br>
--John<br>
<br>
</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</body>
</html>