This fix has a long discussion, so I decided to look closely to it, here is one 
more proposal:

Bug: https://bugs.openjdk.java.net/browse/JDK-8213535
Fix: http://cr.openjdk.java.net/~serb/8213535/webrev.00

Here are some thoughts about the size of the components based on the text:

    Some of the components calculate the size/PreferedSize based on the 
contains the text. The size of the text maybe calculated only if proper 
GraphicsConfiguration is used, because different GC may have different default 
transform and as a result different font metrics and as a result, the same text 
using the same font will be rendered differently.

Here are common steps which are occurred in the application:
 1. The component is not added to any container/window and some default font 
render context is used, if the application request the size of the component it 
will be calculated based on this default context.
 2. If the component is added to the container, it will use render context 
based on the graphics configuration of the container.
 3. The non-displayable window by default use graphics config of the main 
screen, and added component should use it as well.
 4. When the window became visible it start to use the proper graphics config, 
and added component should use it as well.

What could go wrong in the steps above:
 1. The component may cache the size/PreferedSize at step 1, and do not update 
it at step 2, or step 4(Example JDK-8201552[1])
 2. The application itself may request the size at step 1, and did not 
recalculate the size after the step 2 or step 4(the current bug)

In the current bug the PopupFactory requests the preferred size of the 
component which is used as a content of the popup before adding this component 
to the frame where the popup should become visible. As a result, when the 
component is added to the frame its size is incorrect since it was calculated 
using different graphics config, and the actual text which should be rendered 
into the popup does not fit this size.

Inside PopupFactory we have three different popup types:
 - the lightweight popup is based on the JPanel and used as a container for the 
JTooltip if it fits the frame size.
 - the medium weight popup used for any other components which fit the frame 
size.
 - the heavy weight popup used for any components which do not fit the frame 
size.


Current bug affects lightweight and medium popups only, because the heavy 
weight popup use its own frame and use proper GC from the beginning.


In the current fix:
  1. The lightweight and medium popups are updated to call pack(NOTE: it is 
implemented as component.setSize(component.getPreferredSize())) after the popup 
is added to the frame.
  2. To minimize possible popup “jumping” around the frame(when we recalculate 
the size), I made popup invisible at the beginning and made it visible after 
adding to the frame.
  3. Note that I delete invalidate/validate call from the reset(), because the 
call to pack() will invalidate the component anyway again.
  4. It is necessary to call revalidate(which is shortcut for 
invalidate/validate) after setVisible=true in the “medium weight” popup because 
“medium weight” uses AWT component as a container and revalidate is not called 
automatically, unlike lightweight popup which use Swing.

I have updated the test created for JDK-8201552:
 - The logic of the test still the same but now we additionally test the adding 
the child component via PopuFactory (PopuFactory will add the component to the 
frame internally), and will assume that updateComponentTreeUI will change 
nothing if the size was calculated properly from the beginning.
- During fix development, I have broken a few tests, and a little bit tweak 
them for the convenience(setLocationRelativeTo was added).


PS: I have found that menu items in some situations do not update its own 
caches when the size is calculated before adding the menu to the frame, this 
case was excluded in the updated test, and I'll file a separate bug for it.

[1] https://bugs.openjdk.java.net/browse/JDK-8201552

Reply via email to