From fbd9f985724995c4dcabf9ab555909c5e50658df Mon Sep 17 00:00:00 2001 From: "Klare, Heiko" Date: Wed, 25 Feb 2026 15:38:20 +0100 Subject: [PATCH] [Win32] Disable obsolete fallback for drawing text without GDI+ A check in GC.drawText() makes the implementation fall back to the text rendering based on glyphs and their positions calculated by GDI even when GDI+ is used in all cases except when it contains specific characters that GDI cannot handle. This was necessary more than a decade ago because specific Chinese characters were not properly rendered by GDI+. But this is quite non-intuitive as in case GDI+/advance mode is enabled the consumer will usually expected GDI+ to be used for rendering. In addition, the problematic scenario from back then works fine now. This change thus adapts the GC.drawText() implementation to use plain GDI+ whenever it is enabled. The fallback code is preserved but only executed if a newly introduced system property is enabled. This allows to switch back to previous behavior in case unexpected regressions are found. The property is to be removed in a future release in case no regressions are found. May fix https://github.com/eclipse-platform/eclipse.platform.swt/issues/3091 --- .../eclipse/swt/graphics/GCWin32Tests.java | 34 ++++++++++++++++++- .../win32/org/eclipse/swt/graphics/GC.java | 15 +++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java index 70ce62fc18..057983cdba 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java @@ -14,6 +14,7 @@ package org.eclipse.swt.graphics; import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.concurrent.*; @@ -60,6 +61,37 @@ public void drawnElementsShouldScaleUpToTheRightZoomLevel() { GC gc = GC.win32_new(shell, new GCData()); gc.getGCData().nativeZoom = zoom * scalingFactor; gc.getGCData().lineWidth = 10; - assertEquals("Drawn elements should scale to the right value", gc.getGCData().lineWidth, gc.getLineWidth() * scalingFactor, 0); + assertEquals("Drawn elements should scale to the right value", gc.getGCData().lineWidth, + gc.getLineWidth() * scalingFactor, 0); + } + + /** + * Regression test for https://github.com/eclipse-platform/eclipse.platform.swt/issues/3091 + */ + @Test + public void test_drawTextLjava_lang_StringII_advanced_unterlined() { + Display display = Display.getDefault(); + FontData defaultFontFata = display.getSystemFont().getFontData()[0]; + defaultFontFata.data.lfUnderline = 1; + Font font = new Font(display, defaultFontFata); + Image image = new Image(display, 100, 100); + try { + GC gc = new GC(image); + gc.setFont(font); + gc.setAdvanced(true); + gc.drawText("Hello World", 10, 50); + ImageData imageData = image.getImageData(); + boolean anyPixelUnderTextIsNotEmpty = false; + for (int i = 0; i < imageData.width * imageData.height; i++) { + if (imageData.getPixel(i % imageData.width, i / imageData.width) != -1) { + anyPixelUnderTextIsNotEmpty = true; + break; + } + } + assertTrue(anyPixelUnderTextIsNotEmpty); + } finally { + image.dispose(); + font.dispose(); + } } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index fa44dbe351..c5b15ef377 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -109,6 +109,8 @@ public final class GC extends Resource { static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6}; static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3}; + private static final String USE_GDI_TEXT_RENDERING_WITH_GDPI = "org.eclipse.swt.internal.win32.useGDITextRenderingWithGDIP"; + /** * Prevents uninitialized instances from being created outside the package. */ @@ -2832,7 +2834,18 @@ private void drawTextInPixels (String string, int x, int y, int flags) { OS.SetBkMode(handle, oldBkMode); } -private boolean useGDIP (long hdc, char[] buffer) { +private boolean useGDIP(long hdc, char[] buffer) { + // If the system property is set to true, then GDI text rendering may be used + // even when GDI+/advanced mode is enabled. + // The property exists to allow backward compatibility with long standing + // behavior of using GDI text rendering even when GDI+ was enabled was enforced, + // introduced because of issues with the GDI+ text rendering a long time ago. In + // case no regressions occur because of using GDI+ text rendering, this property + // should be removed and GDI+ text rendering should be used by default when + // GDI+/advanced mode is enabled. + if (!Boolean.getBoolean(USE_GDI_TEXT_RENDERING_WITH_GDPI)) { + return true; + } short[] glyphs = new short[buffer.length]; OS.GetGlyphIndices(hdc, buffer, buffer.length, glyphs, OS.GGI_MARK_NONEXISTING_GLYPHS); for (int i = 0; i < glyphs.length; i++) {