-
Notifications
You must be signed in to change notification settings - Fork 166
[GTK] GC#copyArea() produces wrong results when source and target area are overlapping #1756
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
HeikoKlare
added a commit
to HeikoKlare/eclipse.platform.swt
that referenced
this issue
Jan 24, 2025
…se-platform#1756 The GC provides a #copyArea() method that copies an area inside the surface of the GC to another area in the same surface. When using a surface directly created via the Cairo API (or with the GDK API on Wayland), this operation is broken. When the source and target area are overlapping and the source is above-left of the target area, the source area will appear replicated in the target area, as Cairo does not perform any buffering but does a linewise/chunkwise write from the source area to the target area. This change fixes the behavior of GC#copyArea() by explicitly buffering the area to be copied. It also removes the existing workaround in images that avoids the instantiation of a surface via the Cairo API, as the reason for that workaround was the issue fixed by this change. Fixes eclipse-platform#1756
HeikoKlare
added a commit
to HeikoKlare/eclipse.platform.swt
that referenced
this issue
Jan 24, 2025
…se-platform#1756 The GC provides a #copyArea() method that copies an area inside the surface of the GC to another area in the same surface. When using a surface directly created via the Cairo API (or with the GDK API on Wayland), this operation is broken. When the source and target area are overlapping and the source is above-left of the target area, the source area will appear replicated in the target area, as Cairo does not perform any buffering but does a linewise/chunkwise write from the source area to the target area. This change fixes the behavior of GC#copyArea() by explicitly buffering the area to be copied. It also removes the existing workaround in images that avoids the instantiation of a surface via the Cairo API, as the reason for that workaround was the issue fixed by this change. An according regression test is added. Fixes eclipse-platform#1756
HeikoKlare
added a commit
to HeikoKlare/eclipse.platform.swt
that referenced
this issue
Jan 24, 2025
…se-platform#1756 The GC provides a #copyArea() method that copies an area inside the surface of the GC to another area in the same surface. When using a surface directly created via the Cairo API (or with the GDK API on Wayland), this operation is broken. When the source and target area are overlapping and the source is above-left of the target area, the source area will appear replicated in the target area, as Cairo does not perform any buffering but does a linewise/chunkwise write from the source area to the target area. This change fixes the behavior of GC#copyArea() by explicitly buffering the area to be copied. It also removes the existing workaround in images that avoids the instantiation of a surface via the Cairo API, as the reason for that workaround was the issue fixed by this change. It improves the behavior of consumers of that functionality on GTK4 and Wayland. An according regression test is added. Fixes eclipse-platform#1756
HeikoKlare
added a commit
to HeikoKlare/eclipse.platform.swt
that referenced
this issue
Jan 24, 2025
…se-platform#1756 The GC provides a #copyArea() method that copies an area inside the surface of the GC to another area in the same surface. When using a surface directly created via the Cairo API (or with the GDK API on Wayland), this operation is broken. When the source and target area are overlapping and the source is above-left of the target area, the source area will appear replicated in the target area, as Cairo does not perform any buffering but does a linewise/chunkwise write from the source area to the target area by default. This change fixes the behavior of GC#copyArea() by explicitly making Cairo first pipe the copied area into an intermediate surface to be painted into the actual target area afterwards. It also removes the existing workaround in images that avoids the instantiation of a surface via the Cairo API, as the reason for that workaround was the issue fixed by this change. It improves the behavior of consumers of that functionality on GTK4 and Wayland. An according regression test is added. Fixes eclipse-platform#1756
HeikoKlare
added a commit
to HeikoKlare/eclipse.platform.swt
that referenced
this issue
Jan 24, 2025
…se-platform#1756 The GC provides a #copyArea() method that copies an area inside the surface of the GC to another area in the same surface. When using a surface directly created via the Cairo API (or with the GDK API on Wayland), this operation is broken. When the source and target area are overlapping and the source is above-left of the target area, the source area will appear replicated in the target area, as Cairo does not perform any buffering but does a linewise/chunkwise write from the source area to the target area by default. This change fixes the behavior of GC#copyArea() by explicitly making Cairo first pipe the copied area into an intermediate surface to be painted into the actual target area afterwards. It also removes the existing workaround in images that avoids the instantiation of a surface via the Cairo API, as the reason for that workaround was the issue fixed by this change. It improves the behavior of consumers of that functionality on GTK4 and Wayland. An according regression test is added. Fixes eclipse-platform#1756
HeikoKlare
added a commit
to HeikoKlare/eclipse.platform.swt
that referenced
this issue
Jan 24, 2025
…se-platform#1756 The GC provides a #copyArea() method that copies an area inside the surface of the GC to another area in the same surface. When using a surface directly created via the Cairo API (or with the GDK API on Wayland), this operation is broken. When the source and target area are overlapping and the source is above-left of the target area, the source area will appear replicated in the target area, as Cairo does not perform any buffering but does a linewise/chunkwise write from the source area to the target area by default. This change fixes the behavior of GC#copyArea() by explicitly making Cairo first pipe the copied area into an intermediate surface to be painted into the actual target area afterwards. It also removes the existing workaround in images that avoids the instantiation of a surface via the Cairo API, as the reason for that workaround was the issue fixed by this change. It improves the behavior of consumers of that functionality on GTK4 and Wayland. An according regression test is added. Fixes eclipse-platform#1756
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The
GC
provides an operationcopyArea()
that is supposed to copy an area inside the GC's surface, i.e., from a source area of the surface into a target area of the same surface. When the source and target area are overlapping, the result is not as expected.Expected Behavior Example
Take the following original surface data:

Let's assume we want to copy the red-marked area down to the yellow-marked area:

Then we would expect the following result:

Actual Behavior Example
The expected result is only achieved under very specific conditions:
The reason for the latter is that for that exact case (creating Image via width/height or size) a very specific workaround has been implemented via
https://bugs.eclipse.org/bugs/show_bug.cgi?id=571166:
eclipse.platform.swt/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java
Lines 1263 to 1267 in 413426e
In all other cases (using GTK4, using Wayland, using an Image created in a different way) you will see this result:

Since this is a derivation from the existing behavior of GTK and the behavior on Windows and MacOS, consumers may experience inconsistent cross-platform behavior, such as in eclipse-platform/eclipse.platform.ui#2740
Cause
The cause for the mentioned issue is in different behavior of copy operations inside the same surface depending on the used API and environment on which you create a surface. The usage of
GDK.gdk_window_create_similar_surface()
on X11 seems to perform some sufficient buffering of the data to be copied inside the same surface. In all other cases, the operation already overwrites its own source region while still reading from in.In the example show above, the area is linewise/chunkwise copied from top-left downwards. When the copy operation reaches the overlapping red/yellow region, is reads already overwritten data to copy and copies that over again. This leads to duplications of the data in the non-overlapping area.
This can be easily experienced in the LineNumberRuler, which we have already seen several years ago in https://bugs.eclipse.org/bugs/show_bug.cgi?id=571166:

Potential Fix
Completely buffering the data to be copied to avoid concurrent overwrites would solve the problem. I will submit a PR for this. There might be better ways directly via the Cairo API.
The text was updated successfully, but these errors were encountered: