Skip to content

Commit 719d847

Browse files
committed
Clean up FontRegistry's legacy collection handling
FontRegistry still handles its collections the way it did before generics: explicit Iterators, casts through Object, and one variable reused for two unrelated values. It also lets FontRecord reach into the registry to retire its own fonts, mixing up who owns that decision. Simplify all of that, and write down what cleanOnDisplayDisposal == false already promises. No behavior change, other than put() now invalidating the replaced record entirely before notifying listeners rather than partly after, so the registry is consistent by the time they run. That listeners already see the new font when notified was untested, so a test now covers it. Assisted-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 5b3e6dd commit 719d847

2 files changed

Lines changed: 54 additions & 44 deletions

File tree

bundles/org.eclipse.jface/src/org/eclipse/jface/resource/FontRegistry.java

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.Collections;
2020
import java.util.Enumeration;
2121
import java.util.HashMap;
22-
import java.util.Iterator;
2322
import java.util.List;
2423
import java.util.Map;
2524
import java.util.MissingResourceException;
@@ -164,23 +163,22 @@ public Font getItalicFont() {
164163
}
165164

166165
/**
167-
* Add any fonts that were allocated for this record to the
168-
* stale fonts. Anything that matches the default font will
169-
* be skipped.
170-
* @param defaultFont The system default.
166+
* Return all of the fonts allocated by the receiver, that is the base
167+
* font and whichever styled variants have been realized so far.
168+
* @return the allocated fonts, never <code>null</code>
171169
*/
172-
void addAllocatedFontsToStale(Font defaultFont) {
173-
//Return all of the fonts allocated by the receiver.
174-
//if any of them are the defaultFont then don't bother.
175-
if (defaultFont != baseFont && baseFont != null) {
176-
staleFonts.add(baseFont);
170+
List<Font> getAllocatedFonts() {
171+
List<Font> allocatedFonts = new ArrayList<>(3);
172+
if (baseFont != null) {
173+
allocatedFonts.add(baseFont);
177174
}
178-
if (defaultFont != boldFont && boldFont != null) {
179-
staleFonts.add(boldFont);
175+
if (boldFont != null) {
176+
allocatedFonts.add(boldFont);
180177
}
181-
if (defaultFont != italicFont && italicFont != null) {
182-
staleFonts.add(italicFont);
178+
if (italicFont != null) {
179+
allocatedFonts.add(italicFont);
183180
}
181+
return allocatedFonts;
184182
}
185183
}
186184

@@ -368,7 +366,10 @@ public FontRegistry(Display display) {
368366
* the <code>Display</code>
369367
* @param cleanOnDisplayDisposal
370368
* whether all fonts allocated by this <code>FontRegistry</code>
371-
* should be disposed when the display is disposed
369+
* should be disposed when the display is disposed. If
370+
* <code>false</code>, this registry never disposes a font by
371+
* itself; the fonts it allocated are retained until
372+
* {@link #clearCaches()} disposes them
372373
* @since 3.1
373374
*/
374375
public FontRegistry(Display display, boolean cleanOnDisplayDisposal) {
@@ -678,19 +679,19 @@ public Font getItalic(String symbolicName) {
678679
*/
679680
private FontRecord getFontRecord(String symbolicName) {
680681
Assert.isNotNull(symbolicName);
681-
Object result = stringToFontRecord.get(symbolicName);
682-
if (result != null) {
683-
return (FontRecord) result;
682+
FontRecord existingRecord = stringToFontRecord.get(symbolicName);
683+
if (existingRecord != null) {
684+
return existingRecord;
684685
}
685686

686-
result = stringToFontData.get(symbolicName);
687+
FontData[] existingFontData = stringToFontData.get(symbolicName);
687688

688689
FontRecord fontRecord;
689690

690-
if (result == null) {
691+
if (existingFontData == null) {
691692
fontRecord = defaultFontRecord();
692693
} else {
693-
fontRecord = createFont(symbolicName, (FontData[]) result);
694+
fontRecord = createFont(symbolicName, existingFontData);
694695
}
695696

696697
if (fontRecord == null) {
@@ -719,31 +720,14 @@ public boolean hasValueFor(String fontKey) {
719720

720721
@Override
721722
protected void clearCaches() {
722-
723-
Iterator<FontRecord> iterator = stringToFontRecord.values().iterator();
724-
while (iterator.hasNext()) {
725-
Object next = iterator.next();
726-
((FontRecord) next).dispose();
727-
}
728-
729-
disposeFonts(staleFonts.iterator());
723+
stringToFontRecord.values().forEach(FontRecord::dispose);
730724
stringToFontRecord.clear();
725+
staleFonts.forEach(Font::dispose);
731726
staleFonts.clear();
732727

733728
displayDisposeHooked.remove(Display.getCurrent());
734729
}
735730

736-
/**
737-
* Dispose of all of the fonts in this iterator.
738-
* @param iterator over Collection of Font
739-
*/
740-
private void disposeFonts(Iterator<Font> iterator) {
741-
while (iterator.hasNext()) {
742-
Object next = iterator.next();
743-
((Font) next).dispose();
744-
}
745-
}
746-
747731
/**
748732
* Hook a dispose listener on the SWT display.
749733
*/
@@ -821,16 +805,26 @@ private void put(String symbolicName, FontData[] fontData, boolean update) {
821805
return;
822806
}
823807

824-
FontRecord oldFont = stringToFontRecord
825-
.remove(symbolicName);
826808
stringToFontData.put(symbolicName, fontData);
809+
invalidate(symbolicName);
827810
if (update) {
828811
fireMappingChanged(symbolicName, existing, fontData);
829812
}
813+
}
830814

831-
if (oldFont != null) {
832-
oldFont.addAllocatedFontsToStale(defaultFontRecord().getBaseFont());
815+
/**
816+
* Drop the realized font record for the given symbolic name, if any, and
817+
* defer disposal of the fonts it had allocated until it is safe to dispose
818+
* them, since they may still be in use. The default font is kept, as it
819+
* stays in use under its own symbolic name.
820+
*/
821+
private void invalidate(String symbolicName) {
822+
FontRecord replacedRecord = stringToFontRecord.remove(symbolicName);
823+
if (replacedRecord == null) {
824+
return;
833825
}
826+
Font defaultFont = defaultFontRecord().getBaseFont();
827+
replacedRecord.getAllocatedFonts().stream().filter(font -> font != defaultFont).forEach(staleFonts::add);
834828
}
835829

836830
/**

tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/resources/FontRegistryTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,22 @@ public void put_firesPropertyChangeOnlyWhenDataActuallyChanges() {
214214
assertEquals(2, events.size());
215215
}
216216

217+
@Test
218+
public void put_notifiesListenersOnlyAfterTheNewFontIsInEffect() {
219+
FontRegistry fontRegistry = new FontRegistry();
220+
fontRegistry.put("myfont", new FontData[] { new FontData("Arial", 12, SWT.NORMAL) });
221+
Font originalFont = fontRegistry.get("myfont");
222+
223+
AtomicReference<Font> fontSeenByListener = new AtomicReference<>();
224+
fontRegistry.addListener(event -> fontSeenByListener.set(fontRegistry.get("myfont")));
225+
226+
fontRegistry.put("myfont", new FontData[] { new FontData("Arial", 18, SWT.NORMAL) });
227+
228+
assertNotEquals(originalFont, fontSeenByListener.get(),
229+
"a listener must not still see the replaced font when it is notified");
230+
assertEquals(18, fontSeenByListener.get().getFontData()[0].getHeight());
231+
}
232+
217233
@Test
218234
public void put_withNewData_disposesOldFontOnlyOnDisplayDispose() {
219235
assumeTrue(OS.isWindows(), "multiple Display instance only allowed on Windows");

0 commit comments

Comments
 (0)