JDK-8132675 : VBox.setVgrow and HBox.setHgrow corrupt following controls when window resized
  • Type: Bug
  • Component: javafx
  • Sub-Component: web
  • Affected Version: 8,9
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: x86_64
  • Submitted: 2015-07-26
  • Updated: 2017-07-13
  • Resolved: 2017-01-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u151Fixed 9Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_60-ea"
Java(TM) SE Runtime Environment (build 1.8.0_60-ea-b24)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
ver 6.1 - Windows 7 Professional, Version 6.1 (Build 7601, Service Pack 1)


A DESCRIPTION OF THE PROBLEM :
Using VBox.setVgrow or HBox.setHgrow causes corruption of the hover image of following controls when the window is resized larger. I have been struggling with this problem for a while so I have written and tested a small, complete example of source code below which reproduces the problem.
In the example an HBox contains textField1 and a following button2. HBox.setHgrow is applied to textField1. When the window is resized wider (much wider) the hover image of button1 becomes corrupted and when the mouse hovers over button1 a large white square is displayed. In the same way if the window is resized taller (much taller) the hover image of button2 is corrupted because it is in a VBox and follows a browser control which has VBox.setVgrow applied to it.

ADDITIONAL REGRESSION INFORMATION: 
The problem occurs on 8u45 and 8u60 and I have reproduced it on Windows 7 and a tablette running Windows 8. I do not know if it occurs on earlier versions.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the source code application below on a computer with a large monitor (1080 x 1920 pixels). The example displays a top toolbar, a web view browser and a bottom toolbar.
Let the example run 10-15 seconds so that the browser completes displaying  www.yahoo.com.
Once the display is stable resize the screen much bigger (you may need to resize up and down several times). At some point when you move the mouse over button1 or button2 you will see that the hover image is corrupted on one or both buttons - a large white box is displayed over the button.
Please persist with the window resizing until the button corruption occurs - once it has occurred the button hover images stay corrupted. This problem is easily repeatable providing you persist a little.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
When you move the mouse cursor over button1 or button2 I expect to see the button highlighted normally and be able to see the button text.
ACTUAL -
When I move the mouse cursor over button1 or button2 (after resizing one or more times) I see a bright, white square and I do not see the button text.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class GrowBug extends Application {
    
    TextField textField1;
    Button button1;
    
    @Override
    public void start(Stage primaryStage) {
        
        HBox toolBar1 = new HBox();
        textField1 = new TextField("Text Field 1");
        HBox.setHgrow(textField1,Priority.ALWAYS);
        button1 = new Button("Button 1");
        toolBar1.getChildren().addAll(textField1,button1);
        
        WebView browser = new WebView();
        browser.getEngine().load("http://www.yahoo.com");
        
        VBox root = new VBox();
        VBox.setVgrow(browser,Priority.ALWAYS);
        
        HBox toolBar2 = new HBox();
        Button button2= new Button("Button 2");
        TextField textField2= new TextField("TextField 2");
        toolBar2.getChildren().addAll(button2,textField2);
        
        root.getChildren().addAll(toolBar1,browser,toolBar2);
        
        Scene scene = new Scene(root, 1024, 800);
        primaryStage.setTitle("HBox.setHgrow and VBox.setVgrow bugs");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Remove the HBox.setHgrow on textField1 and button1 will no longer become corrupted.
Remove the VBox.setVgrow on the browser and button 2 will no longer become corrupted.
You can also avoid inserting controls in an HBox or VBox AFTER a control which has setHgrow or setVgrow applied, but these workarounds are very restrictive.


Comments
changeset: 3e5199e28a08 user: arajkumar date: Sat Jan 07 23:58:04 2017 +0530 description: 8132675: VBox.setVgrow and HBox.setHgrow corrupt following controls when window resized Reviewed-by: ghb, mbilla, kcr URL: http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/3e5199e28a08
07-01-2017

+1
04-01-2017

+1
03-01-2017

+1
03-01-2017

Please review the new webrev : http://cr.openjdk.java.net/~arajkumar/8132675/webrev.01 This time I have used ScrollbarComposite to implement the FX scrollbar. Previously posted patch has issues when WebCore::Scrollbar instance changes after paint event, due to this while doing scrolling "thumb" is not properly updated as per mouse move position. New webrev needs only ScrollbarPart's(like forward, backward, track) rectangle from platform, rest of the calculations are implemented by ScrollbarComposite.
27-12-2016

I do see the behaviour change with constant thumb width scrollbars[1]. While trying to move the thumb, thumb move independently regardless of mouse position and reaches the end quite fast. It is not happening without this change. The POC patch which I posted earlier (fix-for-growbug-02.patch) which uses ScrollbarComposite works as expected. [1] http://www.w3schools.com/cssref/tryit.asp?filename=trycss_overflow
26-12-2016

+1
22-12-2016

+1, Tested on Overflow i.e http://www.w3schools.com/cssref/tryit.asp?filename=trycss_overflow, I belive you have tested on similar test content which had scrollable iframe along with window resized.
22-12-2016

Thanks [~kcr]. Filed a new bug JDK-8132675 to deal with thickness issue.
22-12-2016

I suggest filing a new bug for dealing with the scrollbar thickness then (and likely not for 9).
21-12-2016

Thanks [~kcr]. I could able to change scrollbar's thickness using the "-fx-padding" property, .scroll-bar { -fx-padding: 0.25em 0.5em; -fx-background-color: red; } Tried with Scene::getStylesheets().add("path/to/my.css") in my application's "start" method. It works properly. But when I defer css file loading using Timer like below, (after 10secs) Timeline timeline = new Timeline(new KeyFrame(Duration.millis(10000), ae -> scene.getStylesheets().add("hello.css"))); timeline.play(); Repaint is not happening(It is a different issue anyhow), but new Scrollbar instance display uses the newly style and old scrollbars are rendered with old style. It is a mixed behaviour. I feel, we should find a new way to deal with the scrollbar thickness.
21-12-2016

Oh, and the flickering while resize is a recent regression that I noticed last week. I will file a new bug for that.
21-12-2016

You should be able to use a CSS style class to control the thickness of your scrollbar track. In any case, that bit of code looks questionable to me. Prior to your proposed fix, have you verified that it always returns the same answer (in the case where it is functioning properly)?
21-12-2016

private boolean thicknessInitialized = false; private void initializeThickness() { if (!thicknessInitialized) { ScrollBar testSB = sbtImpl.getTestSBRef(); if (testSB == null) { return; } int thickness = (int) testSB.prefWidth(-1); if (thickness != 0 && ScrollBarTheme.getThickness() != thickness) { ScrollBarTheme.setThickness(thickness); } thicknessInitialized = true; } } In the above code snipper from ScrollBarWidget.java, Scrollbar thickness is calculated multiple times (for each ScrollBarWidget instance). I assume thickness will not change through the entire Application lifecycle and planning to change the thickness calculation once per Application. [~jgiles], [~kcr], Is there any way to change scrollbar's thickness globally, for all instances? via CSS or some other way? I think above piece of code may be the root cause for JDK-8162618. Since we use special instance of ScrollBarWidget(testSB<Ref>) for state retrival. e.g. Each time ScrollBarThemeImpl::getThumbPosition, we mutate special instance with given scrollbar property and retrive the postion from it. Fix which I have proposed for the current issue possibly solving JDK-8162618 because we are not mutating special instance (testSB<Ref>) instance.
21-12-2016

Thanks [~arajkumar]. I tested by reverting the above patch and i still see flickering issue (which is not seen in earlier versions of JDK 9) and looks like flickering is a regression.
21-12-2016

Thanks [~mbilla]. But I could see the flickering even without my changes on Windows. Please revert my change and try.
21-12-2016

Tested the above patch for JDK-8162618 - "Scrollbars get deformed after resizing window when msn.com is loaded" and the issue JDK-8162618 is not reproducible. But now i see lot of flickering while resizing the webview. I will do more testing and will post review comments.
21-12-2016

FX Scrollbar integration in WebKit: WebCore delegates scrollbar rendering to platform through ScrollbarTheme.h interface. For JavaFX, ScrollbarThemeJava acts as an bridge between JavaFX and WebKit. ScrollBarWidget.java has the required implementation to paint the scrollbar. Prior to this fix, ScrollbarWidget instance will be created when first paint request is made by WebKit. All scrollbar related properties (thumb position, track length,..etc) will be retrieved using a special ScrollBarWidget instance(named "testSBRef") which during ScrollBarThemeImpl construction. Special instance ("testSBRef") will be modified according to the current state of WebCore's "Scrollbar" instance, then it's state will be retrieved. Problem Analysis: The given test case(GrowBug.java) has 5 controls (2 x buttons, 2 x textfield, 1 x webview) and laid out in the scene using "VBox(HBox(textfiled, button), webview, HBox(button, textfield))". Also test loads "yahoo.com" into the webview instance which implicitly creates and displays ScrollBarWidget. Problem occurs when user resizes the host window.When resizing a FX Application hosting Window, all FX controls which is being displayed also will be resized. So as like other controls, WebView and it's children ScrollBar also will be resized. Resize event will notified to native WebPage instance using WebViewHelper.doUpdatePeer method. When native instances of WebView gets resize notification, it will try to resize all HTML elements, and calls ScrollbarThemeJava::thumbPosition for HTML layouting. ScrollbarThemeJava::thumbPosition calls Java side ScrollBarThemeImpl::getThumbPosition, which adjusts the special scrollbar instance("testSBRef") to get the position. So we are trying to change Node's state when it is updating it's state to Peer. Solution: Don't use special ScrollBarWidget instance to get ScrollBar's state, because we need call ScrollBarThemeImpl::adjustScollBar to change it's state according to WebCore's Scrollbar (and causes undesired side effects). After this fix, special instance will be only used to calculate Scrollbar's thickness. http://cr.openjdk.java.net/~arajkumar/8132675/webrev
21-12-2016

Attached a less intrusive fix which utilizes old way of Scrollbar binding.
20-12-2016

Below is a less intrusive workaround, diff -r 4272317a42ad modules/javafx.web/src/main/java/com/sun/javafx/sg/prism/web/NGWebView.java --- a/modules/javafx.web/src/main/java/com/sun/javafx/sg/prism/web/NGWebView.java Mon Dec 12 16:25:29 2016 -0800 +++ b/modules/javafx.web/src/main/java/com/sun/javafx/sg/prism/web/NGWebView.java Fri Dec 16 10:55:53 2016 +0000 @@ -27,6 +27,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import com.sun.webkit.Invoker; import com.sun.javafx.geom.BaseBounds; import com.sun.javafx.geom.RectBounds; import com.sun.javafx.geom.transform.BaseTransform; @@ -60,7 +61,9 @@ height = h; geometryChanged(); if (page != null) { - page.setBounds(0, 0, (int)w, (int)h); + Invoker.getInvoker().postOnEventThread(() -> { + page.setBounds(0, 0, (int)w, (int)h); + }); } } } But could see the empty white background while resizing the window.
16-12-2016

Tried with ScrollbarThemeComposite. It seems to be working. Attached a POC patch. Working on a formal solution.
16-12-2016

There is a platform independent ScrollBarTheme implementation available(Refer ScrollbarThemeComposite.h), it takes care of returning the state of an scrollbar (like thumb size, thumb position, ..etc) to WebCore. We just need to paint the scrollbar based on it's state. We can mutate the state of scrollbar during WebView's paint record operation, because it runs on valid state. All other WebKit ports{win, mac, gtk} uses ScrollbarThemeComposite. I'm going to try a quick POC using the same.
16-12-2016

Thanks [~kcr]. According to the documentation of Region.resize(..) method must be called by it's parent during layout. Also we are calling ScrollBar.setValue() while updating the peer, which is again changes the Node's translation value. I think we shouldn't change any state of WebView's ScrollBarWidget when we are in peer updation state.
15-12-2016

Root cause: When we are syncing between Node and Node::Peer, WebView changes one of it's children(ScrollbarWidget) size during updatePeer which causes Node::transforedBoundsChanged() event and it invalidates the Node::txBounds state. Once the NodeHelper.updatePeer(..) completes, we are clearing the Node's dirty bits. Due to this Node::txBounds never getting updated. Below is the problematic callstack, java.lang.Exception: Stack trace at java.base/java.lang.Thread.dumpStack(Thread.java:1435) ================================================================ at javafx.graphics/javafx.scene.Node.transformedBoundsChanged(Node.java:4043) ================================================================ at javafx.graphics/javafx.scene.Node.localBoundsChanged(Node.java:4024) at javafx.graphics/javafx.scene.Node.doGeomChanged(Node.java:4010) at javafx.graphics/javafx.scene.Node.access$700(Node.java:387) at javafx.graphics/javafx.scene.Node$1.doGeomChanged(Node.java:450) at javafx.graphics/com.sun.javafx.scene.NodeHelper.geomChangedImpl(NodeHelper.java:198) at javafx.graphics/com.sun.javafx.scene.NodeHelper.geomChanged(NodeHelper.java:139) at javafx.graphics/javafx.scene.Parent.childBoundsChanged(Parent.java:1887) at javafx.graphics/javafx.scene.Node.notifyParentOfBoundsChange(Node.java:4089) at javafx.graphics/javafx.scene.Node.transformedBoundsChanged(Node.java:4050) at javafx.graphics/javafx.scene.Node.localBoundsChanged(Node.java:4024) at javafx.graphics/javafx.scene.Node.doGeomChanged(Node.java:4010) at javafx.graphics/javafx.scene.Node.access$700(Node.java:387) at javafx.graphics/javafx.scene.Node$1.doGeomChanged(Node.java:450) at javafx.graphics/com.sun.javafx.scene.NodeHelper.geomChangedImpl(NodeHelper.java:198) at javafx.graphics/com.sun.javafx.scene.NodeHelper.geomChanged(NodeHelper.java:139) at javafx.graphics/javafx.scene.layout.Region.widthChanged(Region.java:1002) at javafx.graphics/javafx.scene.layout.Region.setWidth(Region.java:985) ================================================================ at javafx.graphics/javafx.scene.layout.Region.resize(Region.java:1493) ================================================================ at javafx.web/com.sun.javafx.webkit.theme.ScrollBarThemeImpl.adjustScrollBar(ScrollBarThemeImpl.java:114) at javafx.web/com.sun.javafx.webkit.theme.ScrollBarThemeImpl.adjustScrollBar(ScrollBarThemeImpl.java:121) at javafx.web/com.sun.javafx.webkit.theme.ScrollBarThemeImpl.getThumbPosition(ScrollBarThemeImpl.java:366) at javafx.web/com.sun.webkit.WebPage.twkSetBounds(Native Method) at javafx.web/com.sun.webkit.WebPage.setBounds(WebPage.java:531) at javafx.web/com.sun.javafx.sg.prism.web.NGWebView.resize(NGWebView.java:63) at javafx.web/javafx.scene.web.WebView.doUpdatePeer(WebView.java:1308) at javafx.web/javafx.scene.web.WebView.access$2400(WebView.java:101) at javafx.web/javafx.scene.web.WebView$11.doUpdatePeer(WebView.java:1328) at javafx.web/com.sun.java.scene.web.WebViewHelper.updatePeerImpl(WebViewHelper.java:67) at javafx.graphics/com.sun.javafx.scene.NodeHelper.updatePeer(NodeHelper.java:104) ================================================================ at javafx.graphics/javafx.scene.Node.syncPeer(Node.java:711) ================================================================ at javafx.graphics/javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2385) at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2533) at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$3(Toolkit.java:366) at java.base/java.security.AccessController.doPrivileged(Native Method) at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:365) at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:392) at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518) at javafx.graphics/com.sun.javafx.tk.quantum.PaintCollector.liveRepaintRenderJob(PaintCollector.java:320) at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$ViewEventNotification.run(GlassViewEventHandler.java:870) at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$ViewEventNotification.run(GlassViewEventHandler.java:830) at java.base/java.security.AccessController.doPrivileged(Native Method) at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleViewEvent$15(GlassViewEventHandler.java:911) at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleViewEvent(GlassViewEventHandler.java:910) at javafx.graphics/com.sun.glass.ui.View.handleViewEvent(View.java:540) at javafx.graphics/com.sun.glass.ui.View.notifyResize(View.java:877) at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:189) at java.base/java.lang.Thread.run(Thread.java:844) I think we should not change any Node's state when we are updating its peer. [~kcr], [~jgiles] Any thoughts on this?
15-12-2016

( Adding [~ckyang] and [~jgiles] to the watch list ) Yes, I agree that we should not be changing a Node's state when updating its peer. All such size calculations should be done during the layout phase and/or in response to a resize event.
15-12-2016

We are creating a dummy scrollbar for hit testing in ScrollBarThemeImpl.java. The dummy scroll bar is not visible, but attached to the screen graph and causes WebView to return invalid bounding box.
13-12-2016

Could reproduce issues in all platforms.
13-12-2016

Looks like the problem is seen when the page renders a scrollbar, while loading yahoo.com, I could see more number of ScrollBarWidget instances. Just removed the scroll bar creation from ScrollbarThemeJava.cpp. Issue is not observed.
12-12-2016

Problem happens only when yahoo.com, other sites are working fine.
09-12-2016

For the given problematic VBox instance, NGNode::transformedBounds field doesn't hold updated bounding box.
08-12-2016

Issue is not observed when using -Dprism.dirtyopts=false. Looks like a regression of JDK-8117746.
07-12-2016

Issue is reproducible with -Dprism.order=sw as well.
06-12-2016

I could reproduce the rendering artifact issue 8u60, 8u73 and 9.
16-06-2016

Since the crash is in Webkit I am changing the subcomponent to reflect this, although it isn't certain that the underlying problem is there.
08-08-2015

The bug reporter sent the following e-mail along with the hs_err file as an attachment. ------------------------------------------------------------------ This is the crash which occurs subsequent to the corruption caused by JDK-8132675 (see comments in my email below) # # A fatal error has been detected by the Java Runtime Environment: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000005c31d8a8, pid=4608, tid=6924 # # JRE version: Java(TM) SE Runtime Environment (8.0_60-b26) (build 1.8.0_60-b26) # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode windows-amd64 compressed oops) # Problematic frame: # C [jfxwebkit.dll+0x7ad8a8] # # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows # # An error report file with more information is saved as: # C:\Develop\NetBeans\InetSURE\hs_err_pid4608.log # # If you would like to submit a bug report, please visit: # http://bugreport.java.com/bugreport/crash.jsp # The crash happened outside the Java Virtual Machine in native code. # See problematic frame for where to report the bug. # ---------------------------------------------------------------------- I saw that you were unable to reproduce JDK-8132675 on 32 bit machines, so I found a 32 bit machine and installed the current version of JDK1.8_60 and was able to easily reproduce the problem with my sample code. Screen resolution on that machine was not very high so I just modified the screen width up (to max) and down several times. When I hovered the mouse over button1, then moved the mouse away I was left with a blank white box and no text visible in button1. I do not know why you were unable to reproduce the problem. You have to resize the screen up (to the max) and down several times and then move the mouse in and out of button1 to see the problem. This problem is also much worse than I thought. While testing my complete application if I go to the point where the controls become corrupted, then continue clicking wildly on different URL's the JVM eventually crashes in native code. If I remove the vGrow, hGrow functions this never happens. You cannot easily do this with the sample code I supplied, but I think if you can find and fix the original bug reported in JDK-8132675 the JVM crash should also disappear. If you want the crash reports anyway I will email them. Please try and reproduce the problem again, if you cannot I will do more work on this.
08-08-2015

I tried for a few minutes on my Windows 7 machine, which has a screen resolution of 1920x1080, and so far I cannot reproduce the bug. I tried it on both 8u45 and a recent build of 8u60. These were both using a 32-bit JVM, so I will also try on a 64-bit JVM.
30-07-2015