Render Nine Patch Bug Fix

So there is a bug with the Image._renderNinePatch when:

There is an ADT idealWidth/Height and you use Image.width/Height percentages:

First playground shows WITHOUT ADT idealWidth/Height and borders look great, properly stretched:

Second playground shows WITH ADT idealWidth/Height and BORDERS ARE CROPPED OUT:

So I had devin.ai track down and fix the issue. And it fixed it perfectly.

We need a fix for nine-patch rendering for BABYLON.GUI.Image when width/height are percentages and ADT has idealWidth/idealHeight.

The current code uses ValueAndUnit.getValue(this.host) (raw %) for idealRatio; the fix is to use resolved pixels from _currentMeasure.

Root cause

  • _renderNinePatch used this._width.getValue(this.host)/idealWidth (and height variant). For percentage sizes, getValue(host) is normalized, not pixels, collapsing slice scaling when ideal* is set.

Fix (2 lines)

  • Compute idealRatio from resolved measure:

    const idealRatio = this.host.idealWidth

    ? this._currentMeasure.width / this.host.idealWidth

    : this.host.idealHeight ? this._currentMeasure.height / this.host.idealHeight : 1;

Safety

  • _currentMeasure is the resolved pixel size post-layout, so pixel-sized images are unchanged; nine-patch math/draw remains identical otherwise.

Repro (before fix)

  • ADT with idealWidth or idealHeight

  • Image: stretch = Image.STRETCH_NINE_PATCH, width = “100%”, height = “100%”, slice props or populateNinePatchSlicesFromImage = true

  • Borders disappear/crop with % sizing; OK with px.

After fix

  • Borders render correctly with % sizing and ADT ideal*.
1 Like

cc @georgie

1 Like

thank you for the fix @MackeyK24 ! Approved :slight_smile:

I think the calculation for idealRatio is not quite right, it should be more like the ADT.idealRatio or better yet , just use the this.host.idealRatio instead of recalculating that when the adt already has it calculated correctly:

Or maybe not, what do you think @georgie ?

Doing some debugging I see that from within image class if i set idealWidth then this.host.idealRatio matches the calc in image because image.currentMeasure.width === adt.getSize().width (1713)

However if i set idealHeight instead, I’m seeing different results , where the idealRatios dont match because image._currentMeasure.height != adt.getSize().height

I also see that when calculating currentMeasure, the ‘cx’ control has width/height ispixel true, while the ‘but’ has them as false

Honestly I’m not 100% sure whether we should be using the currentMeasure height or the ADT height – but they do produce slightly different visual results
currentMeasure

If i compare to the asset itself,it does seem like the bottom image (using host idealRatio) is more true to what we’d want
panel.9.png (446×446)

If you agree, please submit a PR that updates the image to use ADT’s idealRatio if it exists!

Hey @georgie

I am not a big fan of the syntax, but i am just following the existing pattern.

So how does this look to you:

Lots of back and forth on these PRs, sorry about that! Here is the fix, thank you for raising it / solving :slight_smile:

Fix RenderNinePatch bug in GUI image by georginahalpern · Pull Request #17030 · BabylonJS/Babylon.js

Thank you @georgie

1 Like