From 0b62b8b9114f60c967fd1504de3533af91f54de6 Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Mon, 24 Aug 2026 16:26:22 +0200 Subject: [PATCH] Add tests for retrieving styled fonts from FontRegistry in non-UI threads FontRegistry supports retrieving a font from a thread that has no Display of its own: rather than failing, it falls back to the default font already realized on the registry's own display. That fallback is only covered by tests for the plain font, not for the bold and italic variants, which still have to be realized when they are requested. Add tests pinning that such a caller still gets a font in the requested style, and that the style is realized on the display the fallback font belongs to rather than on an arbitrary one. The latter matters because creating a Font without a device does not fail: SWT substitutes Display.getDefault(). With a single display that happens to be correct, with more than one it need not be, and a styled font can end up on a different display than the record holding it. Assisted-by: Claude Opus 5 --- .../tests/resources/FontRegistryTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/resources/FontRegistryTest.java b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/resources/FontRegistryTest.java index 78d071ff296..a2857e620ec 100644 --- a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/resources/FontRegistryTest.java +++ b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/resources/FontRegistryTest.java @@ -299,4 +299,54 @@ public void getFontDataAndGetDescriptor_fallBackToDefaultForUnregisteredName() { assertEquals(defaultDescriptor, fallbackDescriptor); } + + @Test + public void getBold_fromNonUIThread_realizesBoldFontOnTheRegistrysDisplay() throws Throwable { + FontRegistry fontRegistry = new FontRegistry(); + fontRegistry.put("myfont", new FontData[] { new FontData("Arial", 12, SWT.NORMAL) }); + // only the plain default font is realized, so the bold variant still has to be created + Font defaultFont = fontRegistry.get(JFaceResources.DEFAULT_FONT); + + Font boldFont = callOnNonUIThread(() -> fontRegistry.getBold("myfont")); + + assertEquals(SWT.BOLD, boldFont.getFontData()[0].getStyle() & SWT.BOLD, + "a caller without a display of its own must still get a bold font"); + assertEquals(defaultFont.getDevice(), boldFont.getDevice(), + "the bold font must be realized on the display the fallback font belongs to"); + } + + @Test + public void getItalic_fromNonUIThread_realizesItalicFontOnTheRegistrysDisplay() throws Throwable { + FontRegistry fontRegistry = new FontRegistry(); + fontRegistry.put("myfont", new FontData[] { new FontData("Arial", 12, SWT.NORMAL) }); + // only the plain default font is realized, so the italic variant still has to be created + Font defaultFont = fontRegistry.get(JFaceResources.DEFAULT_FONT); + + Font italicFont = callOnNonUIThread(() -> fontRegistry.getItalic("myfont")); + + assertEquals(SWT.ITALIC, italicFont.getFontData()[0].getStyle() & SWT.ITALIC, + "a caller without a display of its own must still get an italic font"); + assertEquals(defaultFont.getDevice(), italicFont.getDevice(), + "the italic font must be realized on the display the fallback font belongs to"); + } + + private static Font callOnNonUIThread(Supplier fontSupplier) throws Throwable { + AtomicReference font = new AtomicReference<>(); + AtomicReference failure = new AtomicReference<>(); + Thread nonUiThread = new Thread(() -> { + try { + font.set(fontSupplier.get()); + } catch (Throwable t) { + failure.set(t); + } + }, "non-UI thread font lookup"); + nonUiThread.start(); + nonUiThread.join(); + + if (failure.get() != null) { + throw failure.get(); + } + return font.get(); + } + }