From 5daeaecc652db1deeba65916142dbfe7436cc587 Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Mon, 28 Aug 2023 18:00:24 +0200 Subject: [PATCH] Correct GC offset calculation #788 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The offset calculation in the GC when having an odd line width is erroneous in case rotation transformations have been applied to the GC. With a rotation of 45°, the calculation even suffers from singularities that result in effectively nothing being drawn. With other transformation properties, off-by-one error occur. This change inverts the offset calculation: Instead of performing a forward transformation of a dummy point whose result is applied to the expected offset, the inverse transformation is applied to the expected offset. This avoids singularities and imprecision in the calculation and ensures that when applying rotations to the GC, the drawing figures are as expected. Fixes #788. --- .../win32/org/eclipse/swt/graphics/GC.java | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) 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 b4dadb51ecc..fb099d220c4 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 @@ -323,25 +323,26 @@ void checkGC(int mask) { data.gdipFont = gdipFont; } if ((state & DRAW_OFFSET) != 0) { - data.gdipXOffset = data.gdipYOffset = 0; - long matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); - PointF point = new PointF(); - point.X = point.Y = 1; - Gdip.Graphics_GetTransform(gdipGraphics, matrix); - Gdip.Matrix_TransformVectors(matrix, point, 1); - Gdip.Matrix_delete(matrix); - float scaling = point.X; - if (scaling < 0) scaling = -scaling; - float penWidth = data.lineWidth * scaling; - if (penWidth == 0 || (((int)penWidth) & 1) == 1) { - data.gdipXOffset = 0.5f / scaling; - } - scaling = point.Y; - if (scaling < 0) scaling = -scaling; - penWidth = data.lineWidth * scaling; - if (penWidth == 0 || (((int)penWidth) & 1) == 1) { - data.gdipYOffset = 0.5f / scaling; + PointF offset = new PointF(); + int effectiveLineWidth = data.lineWidth < 1 ? 1 : Math.round(data.lineWidth); + // In case the effective line width is odd, add (0.5, 0.5) to coordinates in + // the coordinate system in which drawings are performed. + // I.e., a line starting at (0,0) will effectively start in pixel right below + // that coordinate with its center at (0.5, 0.5). + if (effectiveLineWidth % 2 == 1) { + offset.X = offset.Y = 0.5f; } + // The offset will be applied to the coordinate system of the GC; so transform + // it from the drawing coordinate system to the coordinate system of the GC by + // applying the inverse transformation as the one applied to the GC and correct + // it by the line width. + long newMatrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); + Gdip.Graphics_GetTransform(gdipGraphics, newMatrix); + Gdip.Matrix_Invert(newMatrix); + Gdip.Matrix_TransformVectors(newMatrix, offset, 1); + Gdip.Matrix_delete(newMatrix); + data.gdipXOffset = Math.abs(offset.X) / effectiveLineWidth; + data.gdipYOffset = Math.abs(offset.Y) / effectiveLineWidth; } return; }