[gtk+/gtk-2-24] Rework GdkPixmapImplQuartz to create CGImage on-demand



commit e6e9eef855d323005c7402e5805c0bcd9fa18ecf
Author: Kristian Rietveld <kris gtk org>
Date:   Tue Oct 19 00:47:33 2010 +0200

    Rework GdkPixmapImplQuartz to create CGImage on-demand
    
    If the data that backs a bitmap context changes, then the CGImage that
    is backed by this data might not always update due to caching effects.
    By creating the CGImage on-demand, we ascertain ourselves that the
    CGImage is up to date.

 gdk/quartz/gdkdrawable-quartz.c |    5 +-
 gdk/quartz/gdkgc-quartz.c       |   33 ++++---
 gdk/quartz/gdkpixmap-quartz.c   |  194 ++++++++++++++++++++++++++++-----------
 gdk/quartz/gdkpixmap-quartz.h   |    3 +-
 gdk/quartz/gdkprivate-quartz.h  |    3 +
 5 files changed, 170 insertions(+), 68 deletions(-)
---
diff --git a/gdk/quartz/gdkdrawable-quartz.c b/gdk/quartz/gdkdrawable-quartz.c
index 2f03f2e..393658c 100644
--- a/gdk/quartz/gdkdrawable-quartz.c
+++ b/gdk/quartz/gdkdrawable-quartz.c
@@ -380,6 +380,7 @@ gdk_quartz_draw_drawable (GdkDrawable *drawable,
     {
       GdkPixmapImplQuartz *pixmap_impl = GDK_PIXMAP_IMPL_QUARTZ (src_impl);
       CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
+      CGImageRef image;
 
       if (!context)
         return;
@@ -392,9 +393,11 @@ gdk_quartz_draw_drawable (GdkDrawable *drawable,
                              pixmap_impl->height);
       CGContextScaleCTM (context, 1.0, -1.0);
 
+      image = _gdk_pixmap_get_cgimage (src);
       CGContextDrawImage (context,
                           CGRectMake (0, 0, pixmap_impl->width, pixmap_impl->height),
-                          pixmap_impl->image);
+                          image);
+      CGImageRelease (image);
 
       gdk_quartz_drawable_release_context (drawable, context);
     }
diff --git a/gdk/quartz/gdkgc-quartz.c b/gdk/quartz/gdkgc-quartz.c
index 9cddd74..eaf4be3 100644
--- a/gdk/quartz/gdkgc-quartz.c
+++ b/gdk/quartz/gdkgc-quartz.c
@@ -84,7 +84,7 @@ create_clip_mask (GdkPixmap *source_pixmap)
    * future, we would look into doing this by hand on the actual raw
    * data.
    */
-  source = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (source_pixmap)->impl)->image;
+  source = _gdk_pixmap_get_cgimage (source_pixmap);
 
   width = CGImageGetWidth (source);
   height = CGImageGetHeight (source);
@@ -322,8 +322,7 @@ _gdk_windowing_gc_copy (GdkGC *dst_gc,
     }
   
   if (src_quartz_gc->clip_mask)
-    dst_quartz_gc->clip_mask =
-      CGImageCreateCopy (GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (src_quartz_gc->clip_mask)->impl)->image);
+    dst_quartz_gc->clip_mask = _gdk_pixmap_get_cgimage (GDK_PIXMAP (src_quartz_gc->clip_mask));
 
   dst_quartz_gc->line_width = src_quartz_gc->line_width;
   dst_quartz_gc->line_style = src_quartz_gc->line_style;
@@ -364,7 +363,7 @@ gdk_quartz_draw_tiled_pattern (void         *info,
   CGImageRef   pattern_image;
   size_t       width, height;
 
-  pattern_image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_tile (gc))->impl)->image;
+  pattern_image = _gdk_pixmap_get_cgimage (GDK_PIXMAP_OBJECT (_gdk_gc_get_tile (gc))->impl);
 
   width = CGImageGetWidth (pattern_image);
   height = CGImageGetHeight (pattern_image);
@@ -372,6 +371,7 @@ gdk_quartz_draw_tiled_pattern (void         *info,
   CGContextDrawImage (context, 
 		      CGRectMake (0, 0, width, height),
 		      pattern_image);
+  CGImageRelease (pattern_image);
 }
 
 static void
@@ -384,7 +384,7 @@ gdk_quartz_draw_stippled_pattern (void         *info,
   CGRect      rect;
   CGColorRef  color;
 
-  pattern_image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl)->image;
+  pattern_image = _gdk_pixmap_get_cgimage (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl);
   rect = CGRectMake (0, 0,
 		     CGImageGetWidth (pattern_image),
 		     CGImageGetHeight (pattern_image));
@@ -396,6 +396,8 @@ gdk_quartz_draw_stippled_pattern (void         *info,
   CGColorRelease (color);
 
   CGContextFillRect (context, rect);
+
+  CGImageRelease (pattern_image);
 }
 
 static void
@@ -408,7 +410,7 @@ gdk_quartz_draw_opaque_stippled_pattern (void         *info,
   CGRect      rect;
   CGColorRef  color;
 
-  pattern_image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl)->image;
+  pattern_image = _gdk_pixmap_get_cgimage (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl);
   rect = CGRectMake (0, 0,
 		     CGImageGetWidth (pattern_image),
 		     CGImageGetHeight (pattern_image));
@@ -427,6 +429,8 @@ gdk_quartz_draw_opaque_stippled_pattern (void         *info,
   CGColorRelease (color);
 
   CGContextFillRect (context, rect);
+
+  CGImageRelease (pattern_image);
 }
 
 void
@@ -611,12 +615,12 @@ _gdk_quartz_gc_update_cg_context (GdkGC                      *gc,
 	{
 	  if (!private->ts_pattern)
 	    {
-	      CGImageRef pattern_image = NULL;
 	      gfloat     width, height;
 	      gboolean   is_colored = FALSE;
 	      CGPatternCallbacks callbacks =  { 0, NULL, NULL };
               struct PatternCallbackInfo *info;
 	      CGPoint    phase;
+              GdkPixmapImplQuartz *pix_impl = NULL;
 
               info = g_new (struct PatternCallbackInfo, 1);
               /* Won't ref to avoid circular dependencies */
@@ -628,17 +632,23 @@ _gdk_quartz_gc_update_cg_context (GdkGC                      *gc,
 	      switch (fill)
 		{
 		case GDK_TILED:
-		  pattern_image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_tile (gc))->impl)->image;
+		  pix_impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_tile (gc))->impl);
+		  width = pix_impl->width;
+		  height = pix_impl->height;
 		  is_colored = TRUE;
 		  callbacks.drawPattern = gdk_quartz_draw_tiled_pattern;
 		  break;
 		case GDK_STIPPLED:
-		  pattern_image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl)->image;
+		  pix_impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl);
+		  width = pix_impl->width;
+		  height = pix_impl->height;
 		  is_colored = FALSE;
 		  callbacks.drawPattern = gdk_quartz_draw_stippled_pattern;
 		  break;
 		case GDK_OPAQUE_STIPPLED:
-		  pattern_image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl)->image;
+		  pix_impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (_gdk_gc_get_stipple (gc))->impl);
+		  width = pix_impl->width;
+		  height = pix_impl->height;
 		  is_colored = TRUE;
 		  callbacks.drawPattern = gdk_quartz_draw_opaque_stippled_pattern;
 		  break;
@@ -646,9 +656,6 @@ _gdk_quartz_gc_update_cg_context (GdkGC                      *gc,
 		  break;
 		}
 
-	      width  = CGImageGetWidth (pattern_image);
-	      height = CGImageGetHeight (pattern_image);
-
 	      phase = CGPointApplyAffineTransform (CGPointMake (gc->ts_x_origin, gc->ts_y_origin), CGContextGetCTM (context));
 	      CGContextSetPatternPhase (context, CGSizeMake (phase.x, phase.y));
 
diff --git a/gdk/quartz/gdkpixmap-quartz.c b/gdk/quartz/gdkpixmap-quartz.c
index 5818d7c..9bf318e 100644
--- a/gdk/quartz/gdkpixmap-quartz.c
+++ b/gdk/quartz/gdkpixmap-quartz.c
@@ -41,27 +41,105 @@ gdk_pixmap_impl_quartz_get_size (GdkDrawable *drawable,
     *height = GDK_PIXMAP_IMPL_QUARTZ (drawable)->height;
 }
 
+static void
+gdk_pixmap_impl_quartz_get_image_parameters (GdkPixmap           *pixmap,
+                                             gint                *bits_per_component,
+                                             gint                *bits_per_pixel,
+                                             gint                *bytes_per_row,
+                                             CGColorSpaceRef     *colorspace,
+                                             CGImageAlphaInfo    *alpha_info)
+{
+  GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (pixmap)->impl);
+  gint depth = GDK_PIXMAP_OBJECT (pixmap)->depth;
+
+  switch (depth)
+    {
+      case 24:
+        if (bits_per_component)
+          *bits_per_component = 8;
+
+        if (bits_per_pixel)
+          *bits_per_pixel = 32;
+
+        if (bytes_per_row)
+          *bytes_per_row = impl->width * 4;
+
+        if (colorspace)
+          *colorspace = CGColorSpaceCreateDeviceRGB ();
+
+        if (alpha_info)
+          *alpha_info = kCGImageAlphaNoneSkipLast;
+        break;
+
+      case 32:
+        if (bits_per_component)
+          *bits_per_component = 8;
+
+        if (bits_per_pixel)
+          *bits_per_pixel = 32;
+
+        if (bytes_per_row)
+          *bytes_per_row = impl->width * 4;
+
+        if (colorspace)
+          *colorspace = CGColorSpaceCreateDeviceRGB ();
+
+        if (alpha_info)
+          *alpha_info = kCGImageAlphaPremultipliedFirst;
+        break;
+
+      case 1:
+        if (bits_per_component)
+          *bits_per_component = 8;
+
+        if (bits_per_pixel)
+          *bits_per_pixel = 8;
+
+        if (bytes_per_row)
+          *bytes_per_row = impl->width;
+
+        if (colorspace)
+          *colorspace = CGColorSpaceCreateDeviceGray ();
+
+        if (alpha_info)
+          *alpha_info = kCGImageAlphaNone;
+        break;
+
+      default:
+        g_assert_not_reached ();
+        break;
+    }
+}
+
 static CGContextRef
 gdk_pixmap_impl_quartz_get_context (GdkDrawable *drawable,
 				    gboolean     antialias)
 {
   GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (drawable);
   CGContextRef cg_context;
-  size_t height;
+  gint bits_per_component, bytes_per_row;
+  CGColorSpaceRef colorspace;
+  CGImageAlphaInfo alpha_info;
+
+  gdk_pixmap_impl_quartz_get_image_parameters (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper,
+                                               &bits_per_component,
+                                               NULL,
+                                               &bytes_per_row,
+                                               &colorspace,
+                                               &alpha_info);
 
   cg_context = CGBitmapContextCreate (impl->data,
-                                      CGImageGetWidth (impl->image),
-                                      CGImageGetHeight (impl->image),
-                                      CGImageGetBitsPerComponent (impl->image),
-                                      CGImageGetBytesPerRow (impl->image),
-                                      CGImageGetColorSpace (impl->image),
-                                      CGImageGetBitmapInfo (impl->image));
+                                      impl->width, impl->height,
+                                      bits_per_component,
+                                      bytes_per_row,
+                                      colorspace,
+                                      alpha_info);
   CGContextSetAllowsAntialiasing (cg_context, antialias);
 
-  /* convert coordinates from core graphics to gtk+ */
-  height = CGImageGetHeight (impl->image);
+  CGColorSpaceRelease (colorspace);
 
-  CGContextTranslateCTM (cg_context, 0, height);
+  /* convert coordinates from core graphics to gtk+ */
+  CGContextTranslateCTM (cg_context, 0, impl->height);
   CGContextScaleCTM (cg_context, 1.0, -1.0);
 
   return cg_context;
@@ -72,7 +150,7 @@ gdk_pixmap_impl_quartz_finalize (GObject *object)
 {
   GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (object);
 
-  CGImageRelease (impl->image);
+  CGDataProviderRelease (impl->data_provider);
 
   _gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
 
@@ -130,6 +208,45 @@ _gdk_pixmap_impl_get_type (void)
   return _gdk_pixmap_impl_quartz_get_type ();
 }
 
+static inline gboolean
+depth_supported (int depth)
+{
+  if (depth != 24 && depth != 32 && depth != 1)
+    {
+      g_warning ("Unsupported bit depth %d\n", depth);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+CGImageRef
+_gdk_pixmap_get_cgimage (GdkPixmap *pixmap)
+{
+  GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (pixmap)->impl);
+  gint bits_per_component, bits_per_pixel, bytes_per_row;
+  CGColorSpaceRef colorspace;
+  CGImageAlphaInfo alpha_info;
+  CGImageRef image;
+
+  gdk_pixmap_impl_quartz_get_image_parameters (pixmap,
+                                               &bits_per_component,
+                                               &bits_per_pixel,
+                                               &bytes_per_row,
+                                               &colorspace,
+                                               &alpha_info);
+
+  image = CGImageCreate (impl->width, impl->height,
+                         bits_per_component, bits_per_pixel,
+                         bytes_per_row, colorspace,
+                         alpha_info,
+                         impl->data_provider, NULL, FALSE, 
+                         kCGRenderingIntentDefault);
+  CGColorSpaceRelease (colorspace);
+
+  return image;
+}
+
 static void
 data_provider_release (void *info, const void *data, size_t size)
 {
@@ -146,10 +263,7 @@ _gdk_pixmap_new (GdkDrawable *drawable,
   GdkDrawableImplQuartz *draw_impl;
   GdkPixmapImplQuartz *pix_impl;
   gint window_depth;
-  CGColorSpaceRef colorspace;
-  CGDataProviderRef data_provider;
-  CGImageAlphaInfo alpha_info;
-  gint bytes_per_row, bits_per_pixel;
+  gint bytes_per_row;
 
   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
   g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
@@ -166,30 +280,8 @@ _gdk_pixmap_new (GdkDrawable *drawable,
   if (depth == -1)
     depth = window_depth;
 
-  switch (depth)
-    {
-    case 24:
-      alpha_info = kCGImageAlphaNoneSkipLast;
-      bytes_per_row = width * 4;
-      bits_per_pixel = 32;
-      colorspace = CGColorSpaceCreateDeviceRGB ();
-      break;
-    case 32:
-      alpha_info = kCGImageAlphaPremultipliedFirst;
-      bytes_per_row = width * 4;
-      bits_per_pixel = 32;
-      colorspace = CGColorSpaceCreateDeviceRGB ();
-      break;
-    case 1:
-      alpha_info = kCGImageAlphaNone;
-      bytes_per_row = width;
-      bits_per_pixel = 8;
-      colorspace = CGColorSpaceCreateDeviceGray ();
-      break;
-    default:
-      g_warning ("Unsupported bit depth %d\n", depth);
-      return NULL;
-    }
+  if (!depth_supported (depth))
+    return NULL;
 
   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
   draw_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (pixmap)->impl);
@@ -198,21 +290,21 @@ _gdk_pixmap_new (GdkDrawable *drawable,
 
   g_assert (depth == 24 || depth == 32 || depth == 1);
 
-  pix_impl->data = g_malloc (height * bytes_per_row);
-  data_provider = CGDataProviderCreateWithData (pix_impl->data, pix_impl->data, 
-						height * bytes_per_row, data_provider_release);
-  pix_impl->image = CGImageCreate (width, height, 8, bits_per_pixel, 
-				   bytes_per_row, colorspace,
-				   alpha_info,
-				   data_provider, NULL, FALSE, 
-				   kCGRenderingIntentDefault);
-  CGDataProviderRelease (data_provider);
-  CGColorSpaceRelease (colorspace);
-
   pix_impl->width = width;
   pix_impl->height = height;
   GDK_PIXMAP_OBJECT (pixmap)->depth = depth;
 
+  gdk_pixmap_impl_quartz_get_image_parameters (pixmap,
+                                               NULL, NULL,
+                                               &bytes_per_row,
+                                               NULL, NULL);
+
+  pix_impl->data = g_malloc (height * bytes_per_row);
+  pix_impl->data_provider = CGDataProviderCreateWithData (pix_impl->data,
+                                                          pix_impl->data,
+                                                          height * bytes_per_row,
+                                                          data_provider_release);
+
   if (depth == window_depth) {
     GdkColormap *colormap = gdk_drawable_get_colormap (drawable);
 
@@ -240,8 +332,6 @@ _gdk_bitmap_create_from_data (GdkDrawable *window,
   pixmap = gdk_pixmap_new (window, width, height, 1);
   impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (pixmap)->impl);
 
-  g_assert (CGImageGetBytesPerRow (impl->image) == width);
-
   /* Bytes per line: Each line consumes an integer number of bytes, possibly
    * ignoring any excess bits. */
   bpl = (width + 7) / 8;
diff --git a/gdk/quartz/gdkpixmap-quartz.h b/gdk/quartz/gdkpixmap-quartz.h
index bb2122a..13cb99f 100644
--- a/gdk/quartz/gdkpixmap-quartz.h
+++ b/gdk/quartz/gdkpixmap-quartz.h
@@ -48,8 +48,7 @@ struct _GdkPixmapImplQuartz
   gint height;
 
   void *data;
-  
-  CGImageRef image;
+  CGDataProviderRef data_provider;
 };
  
 struct _GdkPixmapImplQuartzClass 
diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h
index ab80332..56379a9 100644
--- a/gdk/quartz/gdkprivate-quartz.h
+++ b/gdk/quartz/gdkprivate-quartz.h
@@ -209,4 +209,7 @@ void        _gdk_quartz_window_queue_translation (GdkWindow *window,
 gboolean    _gdk_quartz_window_queue_antiexpose  (GdkWindow *window,
                                                   GdkRegion *area);
 
+/* Pixmap */
+CGImageRef _gdk_pixmap_get_cgimage (GdkPixmap *pixmap);
+
 #endif /* __GDK_PRIVATE_QUARTZ_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]