Created attachment 270084 [details]
Scaling disabled. No difference between visual line width of 0 and 1. Rectangles are directly drawn next to each other
Created attachment 270085 [details]
Code used for testing the issue.
See in GC, lineWidth '0' is actually a hint, refer JavaDoc of GC.setLineWidth(): Note that line width of zero is used as a hint to indicate that the fastest possible line drawing algorithms should be used. This means that the output may be different from line width one. SWT doesn't claim that output for lineWidth 0 and 1 to be same or different. (In reply to Lothar Lattermann from comment #1) > Created attachment 270084 [details] > Scaling disabled. No difference between visual line width of 0 and 1. > Rectangles are directly drawn next to each other This attachment is at 100% zoom, so both lineWidth 0 and 1 are treated as same i.e. 1(because 1 is the fastest to draw) (In reply to Lothar Lattermann from comment #0) > Created attachment 270083 [details] > OS scaling enabled. Visible difference between line width 0 and 1. > Rectangles drawn with gap between them. This attachment is at 200% zoom, so SWT will autoScale the coordinates/width information as below: - lineWidth 0 is treated as 1(which is fastest to draw) - lineWidth 1 is treated as 2(which is autoScaled) - lineWidth 2 is treated as 4(which is autoScaled) This justifies the behavior mentioned in this bug. (In reply to Lothar Lattermann from comment #2) > Created attachment 270085 [details] > Code used for testing the issue. One more point, which I got to know from Lakshmi, regarding the overlapping rectangles drawn at lineWidth 2(issue seen on both 100% and 200% zoom), am precisely referring below code from your code snippet: gc.setLineWidth(2); gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_RED)); gc.drawRectangle(10, 50, 20, 20); //rect1 gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_GREEN)); gc.drawRectangle(31, 50, 20, 20); //rect2 ------------------------------------------------------------------------------ Above client code is not correct for x position of second rectangle, which should have been calculated like below: rect2.x = rect1.x + rect1.width + lineWdith So, rect2.x = 10 + 20 + 2 which makes, rect2.x = 32 Which this value fixed in client code, Overlapping problem is resolved. Created attachment 272365 [details] Additional samples (In reply to Niraj Modi from comment #4) I think there are issues in regards to **scaling** and using the GC to draw directly. Two of those are: 1) Lines with line width 0, while not drawn thicker (scaled), use indeed up more than 1px space and consequently cannot be drawn adjacent to each other [1, 2, 3]. 2) Regardless of width it is not possible to position lines exactly (on an exact pixel) other than transforming lines. This becomes a problem for example when lines are drawn together with filled objects such as rectangles like custom widgets do (for example NatTable [4, 5, 6, 7) or when lines with width 0 are to be drawn adjacent to each other [1]. The reason for 1) appears to be that while a width of 0 is not scaled **coordinates != 0 are always scaled**. Consequently a line with width = 0 and x1 = 0 and y1 = y2 = 1 and x2 = 70 will be scaled to width = 0 and x1 = 0 and y1 = y2 = 2 and x2 = 140. Thus the line is not scaled in width or transformed horizontally (x1 = 0) but transformed vertically (y1 = y2 = 2) and scaled in length (x2 = 140). As a result however, coordinates like y1 = y2 = 1 are not reachable directly. The calculation are done at: GC#setLineWidth(int lineWidth) { lineWidth = DPIUtil.autoScaleUp (drawable, lineWidth); setLineWidthInPixels(lineWidth); } Display#autoScaleUpUsingNativeDPI (int size) { if (nativeDeviceZoom == 100 || size == SWT.DEFAULT) return size; float nativeScaleFactor = nativeDeviceZoom / 100f; return Math.round (size * nativeScaleFactor); // width being 0 returns 0; yet, } // coordinates != 0 are always // scaled/transformed ignorant of width // -> lines with width 0 are partly // scaled/transformed GC#drawLine (int x1, int y1, int x2, int y2) { // should this method only scale when x1 = DPIUtil.autoScaleUp (drawable, x1); // width > 0? x2 = DPIUtil.autoScaleUp (drawable, x2); // because coordinates are scaled devs y1 = DPIUtil.autoScaleUp (drawable, y1); // cannot hit an exact pixel anymore y2 = DPIUtil.autoScaleUp (drawable, y2); drawLineInPixels(x1, y1, x2, y2); // should this be API enabling developers } // create workarounds? Please note: When scaling is turned off the above mentioned issues do not come into play and everything works as expected/intended. Please note: (To my knowledge) the API provides developers with no means to adjust/influence the scaling. Only the VM switch swt.autoScale may be used. For example developers could hint the direction in which direction the width should grow or that only fonts may be scaled or even temporarily disable scaling completely. Please note: Whilst focusing on line drawing the issues apply to points, etc. as well. Please see https://www.eclipse.org/forums/index.php/t/1088692/ for more information. What the image shows: [1] line width 0 due to scaling lines cannot be drawn adjacent to each other drawing a line at y +1 will results in the line "jumping" [2] line width 1 line can be drawn next to each other but will be transformed by the scaling factor. [3] line width 0 using transformation lines can be drawn adjacent to each other because we can use float values such as .5 . As an example how NatTale is suffering from those issues we provide examples 4 - 7. With scaling enabled it is not possible (without transform) to draw a line filling the gap between rectangles. [4] line width 0 line does not fill the gap between 2 rectangles which are drawn 1 pixel below each other. it is not possible to draw to line below each other either as a workaround. [5] line width 1 line is scaled but cannot be drawn exactly in the gap between the two rectangles because the line grows to the outside/up [6] line width 0 same as [4] but with ++y to emphasize that the line is "jumping" and that consequently it is not possible to fill the gap between 2 rectangles which are drawn 1 pixel below each other [7] line width 1 same as [5] but with ++y to emphasize that the line is "jumping" and that consequently it is not possible to fill the gap between 2 rectangles which are drawn 1 pixel below each other Those issues make it nearly impossible/too expensive to create custom widgets which can be used in non-scaled and scaled environments. The Eclipse IDE suffers from this as well whenever it uses a custom drawn widget like the tabs for example. Created attachment 272366 [details]
Additional sample code
(In reply to Niraj Modi from comment #4) > (In reply to Lothar Lattermann from comment #2) > > Created attachment 270085 [details] > > Code used for testing the issue. > > One more point, which I got to know from Lakshmi, regarding the overlapping > rectangles drawn at lineWidth 2(issue seen on both 100% and 200% zoom), am > precisely referring below code from your code snippet: > gc.setLineWidth(2); > gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_RED)); > gc.drawRectangle(10, 50, 20, 20); //rect1 > gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_GREEN)); > gc.drawRectangle(31, 50, 20, 20); //rect2 > ----------------------------------------------------------------------------- > - > Above client code is not correct for x position of second rectangle, which > should have been calculated like below: > rect2.x = rect1.x + rect1.width + lineWdith > So, rect2.x = 10 + 20 + 2 > which makes, rect2.x = 32 > > Which this value fixed in client code, Overlapping problem is resolved. We will open anther ticket to describe this issue in more detail: In short: developers cannot hint in which direction a value should be scaled/grow (for example left to right or top to bottom) The way the current code works a line with width 1 and y1 = y2 = 0 will be scaled outside of the visible area for example and thus be cut off. Created attachment 272494 [details] Snippet: Mixing lineWidth=0 with lineWidth 1,2 at 200% zoom value. (In reply to Lothar Lattermann from comment #7) > We will open anther ticket to describe this issue in more detail: > In short: developers cannot hint in which direction a value should be > scaled/grow (for example left to right or top to bottom) > The way the current code works a line with width 1 and y1 = y2 = 0 will be > scaled outside of the visible area for example and thus be cut off. I created one test snippet where-in am mixing lineWidth=0 with lineWidth 1,2 at 200% zoom value. Created attachment 272496 [details]
Screen-shot: Mixing lineWidth=0 with lineWidth 1,2 at 200% zoom value.
Since SWT coordinate system is integer based, we don't see any upfront solution to '0' lineWidth behavior at 200%zoom. Ideas are welcome here.
(In reply to Niraj Modi from comment #9) > Since SWT coordinate system is integer based, we don't see any upfront > solution to '0' lineWidth behavior at 200%zoom. Ideas are welcome here. Conrad, any ideas here? (In reply to Niraj Modi from comment #9) > Created attachment 272496 [details] > Screen-shot: Mixing lineWidth=0 with lineWidth 1,2 at 200% zoom value. > > Since SWT coordinate system is integer based, we don't see any upfront > solution to '0' lineWidth behavior at 200%zoom. Ideas are welcome here. There is no clear solution to lineWidth zero problem and hence it's not recommended to mix line width zero with other line widths in high DPI scenario. For clarity, we will mention the same in JavaDoc of GC.setLineWidth() method. Will share a gerrit shortly for 4.8 M7 New Gerrit change created: https://git.eclipse.org/r/122254 Gerrit change https://git.eclipse.org/r/122254 was merged to [master]. Commit: http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=9a393e8677dae90cf87b17188eb1104b7ca70f93 (In reply to Eclipse Genie from comment #13) > Gerrit change https://git.eclipse.org/r/122254 was merged to [master]. > Commit: > http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/ > ?id=9a393e8677dae90cf87b17188eb1104b7ca70f93 Resolving now. Verified in I20180507-2205 on Win7. |
Created attachment 270083 [details] OS scaling enabled. Visible difference between line width 0 and 1. Rectangles drawn with gap between them. When a line is drawn with the GC in a HiDPI/Windows 10 environment with OS scaling enabled and the width of the line is set to 0 the acutal drawn line width is not scaled. When the line width is set to 1 the line width howver is scaled. Thus the visual end result between machines with or without OS scaling differs and is consequently not portable. We attached two screenshots to visualize the problem with scaling enabled (osScaling200percent.png) as well as the code we tested the issue with. We also attached a screen shot run the same test with scaling disabled (osScalingOff.png) to show the difference. We think this is a bug because on a machine without OS scaling the visual result using a line width 0 or 1 is the same. With scaling Rectangles will not be joint or lines cannot be drawn directly next to each other. Using the switch -Dswt.autoScale has no effect with line width 0 and thus does not remedy the issue. The dimension of the rectangle will be scaled but not the line width. Using a line width >= 1, the line width will be scaled however. We tested with Windows 10 (Version 1703 Build 15063.483) with a 3840x2160 resulution and 200% scaling (OS default with that resolution). The SWT Version used was 3.106.0.v20170608-0516 in Eclipse Oxygen. When a line is drawn with the GC in a HiDPI/Windows 10 environment with OS scaling enabled and the width of the line is set to 0 the acutal drawn line width is not scaled. When the line width is set to 1 the line width howver is scaled. Thus the visual end result between machines with or without OS scaling differs and is consequently not portable.