<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <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.</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...</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.</p>
    <p>--John<br>
    </p>
    <div class="moz-cite-prefix">On 16/04/2025 17:04, Nir Lisker wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CA+0ynh9e0ooe4eDOENKSkxbqP2RRZ2qj9-etM9KmypZXkijjKg@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">Sounds good. Have you tried a prototype
        implementation for a built-in JavaFX control/Pane, just to see
        how well it works?</div>
      <br>
      <div class="gmail_quote gmail_quote_container">
        <div dir="ltr" class="gmail_attr">On Wed, Apr 16, 2025 at
          5:50 PM Andy Goryachev <<a
            href="mailto:andy.goryachev@oracle.com"
            moz-do-not-send="true" class="moz-txt-link-freetext">andy.goryachev@oracle.com</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div class="msg-1880730255040356136">
            <div style="overflow-wrap: break-word;" lang="EN-US">
              <div class="m_-1880730255040356136WordSection1">
                <p class="MsoNormal"><span
style="font-size:11pt;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></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16""> </span></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16"">(and I
                    like Michael's suggestion of naming the method
                    requestLayoutChildren())</span></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16""> </span></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16"">-andy</span></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16""> </span></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16""> </span></p>
                <p class="MsoNormal"><span
style="font-size:11pt;font-family:"Iosevka Fixed SS16""> </span></p>
                <div
id="m_-1880730255040356136mail-editor-reference-message-container">
                  <div>
                    <div>
                      <div
style="border-right:none;border-bottom:none;border-left:none;border-top:1pt solid rgb(181,196,223);padding:3pt 0in 0in">
                        <p class="MsoNormal" style="margin-bottom:12pt"><b><span
                              style="font-size:12pt;color:black">From:
                            </span></b><span
                            style="font-size:12pt;color:black">openjfx-dev
                            <<a
                              href="mailto:openjfx-dev-retn@openjdk.org"
                              target="_blank" moz-do-not-send="true"
                              class="moz-txt-link-freetext">openjfx-dev-retn@openjdk.org</a>>
                            on behalf of John Hendrikx <<a
                              href="mailto:john.hendrikx@gmail.com"
                              target="_blank" moz-do-not-send="true"
                              class="moz-txt-link-freetext">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" moz-do-not-send="true"
                              class="moz-txt-link-freetext">openjfx-dev@openjdk.org</a>
                            <<a href="mailto:openjfx-dev@openjdk.org"
                              target="_blank" moz-do-not-send="true"
                              class="moz-txt-link-freetext">openjfx-dev@openjdk.org</a>><br>
                            <b>Subject: </b>Unnecessary layouts; TLDR;
                            new method "requestLocalLayout"</span></p>
                      </div>
                      <div>
                        <p class="MsoNormal" style="margin-bottom:12pt"><span
                            style="font-size:11pt">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>
                            <br>
                          </span></p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>