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 75889472a5..78c72cdfbe 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 @@ -680,7 +680,22 @@ static long createGdipFont(long hDC, long hFont, long graphics, long fontCollect if (outFont != null && font != 0) { long hHeap = OS.GetProcessHeap(); long pLogFont = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, LOGFONT.sizeof); - Gdip.Font_GetLogFontW(font, graphics, pLogFont); + if (graphics != 0) { + // Font_GetLogFontW applies the graphics's world transform when converting the + // font size to LOGFONT units. A non-identity user transform would cause lfHeight + // to be scaled, producing an incorrectly-sized GDI font for GetTextMetrics. + // Temporarily set identity so the LOGFONT reflects device-pixel metrics. + long savedMatrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); + Gdip.Graphics_GetTransform(graphics, savedMatrix); + long identityMatrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); + Gdip.Graphics_SetTransform(graphics, identityMatrix); + Gdip.Font_GetLogFontW(font, graphics, pLogFont); + Gdip.Graphics_SetTransform(graphics, savedMatrix); + Gdip.Matrix_delete(identityMatrix); + Gdip.Matrix_delete(savedMatrix); + } else { + Gdip.Font_GetLogFontW(font, graphics, pLogFont); + } outFont[0] = OS.CreateFontIndirect(pLogFont); OS.HeapFree(hHeap, 0, pLogFont); } diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java index 2806c1d865..ba27c86d0b 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java @@ -730,6 +730,45 @@ public void test_getFontMetrics() { assertTrue(fm.getHeight() > 0); } +/** + * Verifies that applying a transform to a GC does not affect the font metrics + * when the font does not exist on the current platform and a fallback font is + * used instead. + * + * @see Issue 2978 + */ +@Test +public void test_getFontMetrics_notAffectedByTransform() { + Font font = new Font(display, "NonExistentSWTTestFont", 24, SWT.NORMAL); + Transform scaleTransform = new Transform(display, 3.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f); + try { + gc.setFont(font); + gc.setTransform(scaleTransform); + double metricsWithTransform = gc.getFontMetrics().getAverageCharacterWidth(); + + gc.setTransform(null); + double metricsAfterClearingTransform = gc.getFontMetrics().getAverageCharacterWidth(); + + gc.setFont(font); + double metricsAfterReSettingFont = gc.getFontMetrics().getAverageCharacterWidth(); + + gc.setTransform(scaleTransform); + double metricsWithTransformAgain = gc.getFontMetrics().getAverageCharacterWidth(); + + assertAll( + () -> assertEquals(metricsWithTransform, metricsAfterClearingTransform, 0, + "Font metrics must not change after clearing the transform"), + () -> assertEquals(metricsAfterClearingTransform, metricsAfterReSettingFont, 0, + "Font metrics must not change when re-setting the font without transform"), + () -> assertEquals(metricsAfterReSettingFont, metricsWithTransformAgain, 0, + "Font metrics must not be scaled when the transform is re-applied") + ); + } finally { + scaleTransform.dispose(); + font.dispose(); + } +} + @Test public void test_getStyle() { Canvas canvas = new Canvas(shell, SWT.NULL);