After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 757187 - Assertion violation in gdk_image_new_for_depth
Assertion violation in gdk_image_new_for_depth
Status: RESOLVED OBSOLETE
Product: gtk+
Classification: Platform
Component: Backend: Quartz
unspecified
Other Mac OS
: Normal blocker
: ---
Assigned To: gtk-quartz maintainers
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2015-10-27 13:16 UTC by Emmanuel Stapf
Modified: 2018-05-02 16:49 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Proposed patch against 2.24.30 (4.91 KB, patch)
2016-07-10 12:11 UTC, Emmanuel Stapf
none Details | Review
Patch using git format-patch command (5.28 KB, patch)
2016-07-10 22:46 UTC, Emmanuel Stapf
none Details | Review
Patch using git format-patch command (5.28 KB, patch)
2016-07-10 22:50 UTC, Emmanuel Stapf
none Details | Review

Description Emmanuel Stapf 2015-10-27 13:16:34 UTC
EiffelStudio does not run under GTK for MacOS using quartz. The issue is an assert violation which causes EiffelStudio to crash.

This violation is:

Gdk:ERROR:gdkimage-quartz.c:330:_gdk_image_new_for_depth: assertion failed: (depth == 24 || depth == 32)

And it is not called directly by our code, but indirectly by a call to "gdk_pixbuf_get_from_drawable".

The same code works fine on MacOS or other platforms using the X11 backend.

You can easily reproduce this bug by downloading and installing EiffelStudio from Homebrew in the hombrew/x11 tap (name is confusing since it is not x11 anymore).

To launch EiffelStudio and observe the crash, type "ec -gui" assuming you have /usr/local/bin in your path. To debug, you need to set 2 environment variables:
- ISE_EIFFEL=/usr/local/Cellar/eiffelstudio/15.08/
- ISE_PLATFORM=macosx-x86-64

Let me know how I can help to solve this issue.

Thanks,
Manu
Comment 1 Emmanuel Stapf 2015-10-27 13:18:11 UTC
I missed one step to debug, you then need to launch

/usr/local/Cellar/eiffelstudio/15.08/studio/spec/macosx-x86-64/bin/ec -gui
Comment 2 John Ralls 2015-10-27 14:21:12 UTC
Sorry, installing your software (never mind Homebrew) to reproduce a bug is not acceptable. Please provide a small example program in C that demonstrates it or at least a link to where gdk_pixbuf_get_from_drawable() is called.

Note, however, that this is an assert. Asserts exist to enforce invariants. In this case, the invariant is that the Quartz backend supports only bit depths of 24 and 32 bits. If your code is trying to use a different bit depth, then you'll have to fix it. If the bit-depth you want is 1, see bug 557780.
Comment 3 Emmanuel Stapf 2016-07-10 02:09:51 UTC
My code definitely wants 1-bit depth as we use them to do our own masking. The assert is in my opinion wrong since the function `depth_supported` reports 1, 24 and 32 as valid depth for GdpPixmap (see line gdkpixmap-quartz.c:214 in version 2.24.30 of GTK) and the code of `_gdk_quartz_image_copy_to_image` do support 1-bit image too.

The solution from bug 557780 is not sufficient.

It will take some time to get a simple reproducible example, but what we do is take a transparent png image, get a GdkPixbuf from it, and split it into 2 GdkImage (actual image and its mask), we use gdk_pixbuf_render_pixmap_and_mask for that.
Comment 4 Emmanuel Stapf 2016-07-10 12:07:35 UTC
Spent a good deal of time debugging and managed to add support for 1-bit pixmap. Along with the proposed fix of bug https://bugzilla.gnome.org/show_bug.cgi?id=768631, I can render things better (still facing some rendering and other various issues but not assert anymore).

diff --git a/gdk/quartz/gdkimage-quartz.c b/gdk/quartz/gdkimage-quartz.c
--- a/gdk/quartz/gdkimage-quartz.c
+++ b/gdk/quartz/gdkimage-quartz.c
@@ -37,15 +37,16 @@ _gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
 				 gint         height)
 {
   GdkScreen *screen;
+  int depth;
   
   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_QUARTZ (drawable), NULL);
   g_return_val_if_fail (image != NULL || (dest_x == 0 && dest_y == 0), NULL);
 
   screen = gdk_drawable_get_screen (drawable);
+  depth = gdk_drawable_get_depth (drawable);
   if (!image)
     image = _gdk_image_new_for_depth (screen, GDK_IMAGE_FASTEST, NULL, 
-				      width, height,
-				      gdk_drawable_get_depth (drawable));
+				      width, height, depth);
   
   if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
     {
@@ -63,7 +64,7 @@ _gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
           return image;
         }
 
-      switch (gdk_drawable_get_depth (drawable))
+      switch (depth)
         {
         case 24:
           bytes_per_row = pix_impl->width * 4;
@@ -112,7 +113,7 @@ _gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
               for (x = 0; x < width; x++)
                 {
                   gint32 pixel;
-	  
+
                   /* 8 bits */
                   pixel = src[0];
                   src++;
@@ -123,7 +124,7 @@ _gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
           break;
 
         default:
-          g_warning ("Unsupported bit depth %d\n", gdk_drawable_get_depth (drawable));
+          g_warning ("Unsupported bit depth %d\n", depth);
           return image;
         }
     }
@@ -146,7 +147,7 @@ _gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
       if (GDK_WINDOW_IMPL_QUARTZ (drawable) == GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (_gdk_root)->impl))
         {
           /* Special case for the root window. */
-	  CGRect rect = CGRectMake (src_x, src_y, width, height);
+          CGRect rect = CGRectMake (src_x, src_y, width, height);
           CGImageRef root_image_ref = CGWindowListCreateImage (rect,
                                                                kCGWindowListOptionOnScreenOnly,
                                                                kCGNullWindowID,
@@ -173,7 +174,7 @@ _gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
         }
       else
         {
-	  NSRect rect = NSMakeRect (src_x, src_y, width, height);
+          NSRect rect = NSMakeRect (src_x, src_y, width, height);
           view = GDK_WINDOW_IMPL_QUARTZ (drawable)->view;
 
           /* We return the image even if we can't copy to it. */
@@ -322,7 +323,7 @@ _gdk_image_new_for_depth (GdkScreen    *screen,
   if (visual)
     depth = visual->depth;
 
-  g_assert (depth == 24 || depth == 32);
+  g_assert((depth == 1) || (depth == 24) || (depth == 32));
 
   image = g_object_new (gdk_image_get_type (), NULL);
   image->type = type;
@@ -333,11 +334,16 @@ _gdk_image_new_for_depth (GdkScreen    *screen,
 
   image->byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
 
-  /* We only support images with bpp 4 */
-  image->bpp = 4;
-  image->bpl = image->width * image->bpp;
-  image->bits_per_pixel = image->bpp * 8;
-  
+  if (depth == 1) {
+    image->bpp = 1;
+    image->bpl = (image->width >> 3) + 1;
+    image->bits_per_pixel = 1;
+  } else {
+      image->bpp = 4;
+      image->bpl = image->width * image->bpp;
+      image->bits_per_pixel = image->bpp * 8;
+  }
+
   image->mem = g_malloc (image->bpl * image->height);
   memset (image->mem, 0x00, image->bpl * image->height);
 
@@ -355,9 +361,14 @@ gdk_image_get_pixel (GdkImage *image,
   g_return_val_if_fail (x >= 0 && x < image->width, 0);
   g_return_val_if_fail (y >= 0 && y < image->height, 0);
 
-  ptr = image->mem + y * image->bpl + x * image->bpp;
-
-  return *(guint32 *)ptr;
+  ptr = image->mem + y * image->bpl;
+  if (image->depth == 1) {
+    guchar data = (image->byte_order == GDK_MSB_FIRST ? (0x80 >> (x & 7)) : (1 << (x & 7)));
+    return (ptr[x >> 3] & data) ? 0x1 : 0x0;
+  } else {
+    ptr += x * image->bpp;
+    return *(guint32 *)ptr;
+  }
 }
 
 void
@@ -366,18 +377,27 @@ gdk_image_put_pixel (GdkImage *image,
 		     gint y,
 		     guint32 pixel)
 {
-  guchar *ptr;
-
-  ptr = image->mem + y * image->bpl + x * image->bpp;
-
-  *(guint32 *)ptr = pixel;
+  guchar *ptr = image->mem + y * image->bpl;
+  if (image->depth == 1) {
+    guchar data = (image->byte_order == GDK_MSB_FIRST ? (0x80 >> (x & 7)) : (1 << (x & 7)));
+    if (pixel) {
+        ptr[x >> 3] |= data;
+    } else {
+        ptr[x >> 3] &= ~data;
+    }
+  } else {
+    ptr += x * image->bpp;
+    *(guint32 *)ptr = pixel;
+  }
 }
 
 gint
 _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
-				   gint        depth)
+                                  gint        depth)
 {
-  if (depth == 24 || depth == 32)
+  if (depth == 1)
+	return 1;
+  else if (depth == 24 || depth == 32)
     return 32;
   else
     g_assert_not_reached ();
Comment 5 Emmanuel Stapf 2016-07-10 12:11:32 UTC
Created attachment 331158 [details] [review]
Proposed patch against 2.24.30
Comment 6 Emmanuele Bassi (:ebassi) 2016-07-10 13:02:32 UTC
Review of attachment 331158 [details] [review]:

Thanks for the patch.

Could you please attach a patch generated by `git format-patch` instead of a diff? This allows proper review and attribution.

::: gdk/quartz/gdkimage-quartz.c
@@ +148,3 @@
         {
           /* Special case for the root window. */
+          CGRect rect = CGRectMake (src_x, src_y, width, height);

This looks like whitespace change; please, skip this.

@@ +175,3 @@
       else
         {
+          NSRect rect = NSMakeRect (src_x, src_y, width, height);

This looks like whitespace change; pleace, skip this.

@@ +324,3 @@
     depth = visual->depth;
 
+  g_assert((depth == 1) || (depth == 24) || (depth == 32));

Coding style: missing space between `g_assert` and opening parenthesis.

@@ +335,3 @@
   image->byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
 
+  if (depth == 1) {

Coding style: braces on a new line, indented.

@@ +339,3 @@
+    image->bpl = (image->width >> 3) + 1;
+    image->bits_per_pixel = 1;
+  } else {

Coding style: `else` and braces go on a separate line.

@@ +363,3 @@
 
+  ptr = image->mem + y * image->bpl;
+  if (image->depth == 1) {

Coding style: braces on a new line.

@@ +366,3 @@
+    guchar data = (image->byte_order == GDK_MSB_FIRST ? (0x80 >> (x & 7)) : (1 << (x & 7)));
+    return (ptr[x >> 3] & data) ? 0x1 : 0x0;
+  } else {

Coding style: `else` and braces go on a separate line.

@@ +379,3 @@
 {
+  guchar *ptr = image->mem + y * image->bpl;
+  if (image->depth == 1) {

Coding style: braces on a new indented line.

@@ +382,3 @@
+    guchar data = (image->byte_order == GDK_MSB_FIRST ? (0x80 >> (x & 7)) : (1 << (x & 7)));
+    if (pixel) {
+        ptr[x >> 3] |= data;

Coding style: too much indentation.

@@ +384,3 @@
+        ptr[x >> 3] |= data;
+    } else {
+        ptr[x >> 3] &= ~data;

Coding style: too much indentation.

@@ +386,3 @@
+        ptr[x >> 3] &= ~data;
+    }
+    if (pixel) {

Coding style: `else` and braces go on a new line.

@@ +397,2 @@
 {
+  if (depth == 1)

I would change this to a switch:

  switch (depth)
    {
    case 1:
      return 1;

    case 24:
    case 32:
      return 32;

    default:
      g_assert_not_reached ();
    }
Comment 7 Emmanuel Stapf 2016-07-10 22:46:22 UTC
Created attachment 331171 [details] [review]
Patch using git format-patch command
Comment 8 Emmanuel Stapf 2016-07-10 22:47:32 UTC
Just resubmitted it now.
Comment 9 Emmanuel Stapf 2016-07-10 22:50:11 UTC
Created attachment 331173 [details] [review]
Patch using git format-patch command

Update patch to use the git format-patch command
Comment 10 Matthias Clasen 2018-02-10 05:13:13 UTC
We're moving to gitlab! As part of this move, we are moving bugs to NEEDINFO if they haven't seen activity in more than a year. If this issue is still important to you and still relevant with GTK+ 3.22 or master, please reopen it and we will migrate it to gitlab.
Comment 11 Emmanuel Stapf 2018-02-10 16:44:41 UTC
It is still imporant for me but I cannot change the status to re-open it.
Comment 12 Emmanuele Bassi (:ebassi) 2018-02-10 18:48:54 UTC
As per comment 11; thanks for your patience!
Comment 13 GNOME Infrastructure Team 2018-05-02 16:49:14 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gtk/issues/580.