gtk2/gdk/quartz/gdkpixmap-quartz.c
Sven Herzberg bd86f2e8fb reviewed by: Richard Hult
2008-07-20  Sven Herzberg  <sven@imendio.com>

	reviewed by: Richard Hult

	Fixes #543868: GdkPixmap is upside down on quartz

	* gdk/quartz/gdkdrawable-quartz.c (gdk_quartz_draw_drawable): flip the
	coordinate space from GTK+ orientation to CoreGraphics orientation
	before calling CoreGraphics code
	* gdk/quartz/gdkgc-quartz.c (gdk_quartz_draw_tiled_pattern): drop the
	coordinate space flipping (we always get it right, now)
	* gdk/quartz/gdkpixmap-quartz.c
	(gdk_pixmap_impl_quartz_get_context): flip the coordinate space when
	creating the CGContextRef


svn path=/trunk/; revision=20870
2008-07-20 19:22:37 +00:00

314 lines
8.4 KiB
C

/* gdkpixmap-quartz.c
*
* Copyright (C) 2005 Imendio AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gdkpixmap.h"
#include "gdkprivate-quartz.h"
static gpointer parent_class;
static void
gdk_pixmap_impl_quartz_init (GdkPixmapImplQuartz *impl)
{
}
static void
gdk_pixmap_impl_quartz_get_size (GdkDrawable *drawable,
gint *width,
gint *height)
{
if (width)
*width = GDK_PIXMAP_IMPL_QUARTZ (drawable)->width;
if (height)
*height = GDK_PIXMAP_IMPL_QUARTZ (drawable)->height;
}
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;
cg_context = CGBitmapContextCreate (impl->data,
CGImageGetWidth (impl->image),
CGImageGetHeight (impl->image),
CGImageGetBitsPerComponent (impl->image),
CGImageGetBytesPerRow (impl->image),
CGImageGetColorSpace (impl->image),
CGImageGetBitmapInfo (impl->image));
CGContextSetAllowsAntialiasing (cg_context, antialias);
/* convert coordinates from core graphics to gtk+ */
height = CGImageGetHeight (impl->image);
CGContextTranslateCTM (cg_context, 0, height);
CGContextScaleCTM (cg_context, 1.0, -1.0);
return cg_context;
}
static void
gdk_pixmap_impl_quartz_finalize (GObject *object)
{
GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (object);
CGImageRelease (impl->image);
_gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gdk_pixmap_impl_quartz_class_init (GdkPixmapImplQuartzClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
GdkDrawableImplQuartzClass *drawable_quartz_class = GDK_DRAWABLE_IMPL_QUARTZ_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gdk_pixmap_impl_quartz_finalize;
drawable_class->get_size = gdk_pixmap_impl_quartz_get_size;
drawable_quartz_class->get_context = gdk_pixmap_impl_quartz_get_context;
}
GType
_gdk_pixmap_impl_quartz_get_type (void)
{
static GType object_type = 0;
if (!object_type)
{
static const GTypeInfo object_info =
{
sizeof (GdkPixmapImplQuartzClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_pixmap_impl_quartz_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixmapImplQuartz),
0, /* n_preallocs */
(GInstanceInitFunc) gdk_pixmap_impl_quartz_init
};
object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_QUARTZ,
"GdkPixmapImplQuartz",
&object_info,
0);
}
return object_type;
}
GType
_gdk_pixmap_impl_get_type (void)
{
return _gdk_pixmap_impl_quartz_get_type ();
}
static void
data_provider_release (void *info, const void *data, size_t size)
{
g_free (info);
}
GdkPixmap*
gdk_pixmap_new (GdkDrawable *drawable,
gint width,
gint height,
gint depth)
{
GdkPixmap *pixmap;
GdkDrawableImplQuartz *draw_impl;
GdkPixmapImplQuartz *pix_impl;
gint window_depth;
CGColorSpaceRef colorspace;
CGDataProviderRef data_provider;
CGImageAlphaInfo alpha_info;
gint bytes_per_row, bits_per_pixel;
g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
g_return_val_if_fail ((width != 0) && (height != 0), NULL);
if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
return NULL;
if (!drawable)
drawable = gdk_screen_get_root_window (gdk_screen_get_default ());
window_depth = gdk_drawable_get_depth (GDK_DRAWABLE (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;
}
pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
draw_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (pixmap)->impl);
pix_impl = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (pixmap)->impl);
draw_impl->wrapper = GDK_DRAWABLE (pixmap);
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;
if (depth == window_depth) {
GdkColormap *colormap = gdk_drawable_get_colormap (drawable);
if (colormap)
gdk_drawable_set_colormap (pixmap, colormap);
}
return pixmap;
}
GdkPixmap *
gdk_bitmap_create_from_data (GdkDrawable *window,
const gchar *data,
gint width,
gint height)
{
GdkPixmap *pixmap;
GdkPixmapImplQuartz *impl;
int x, y, bpl;
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail ((width != 0) && (height != 0), NULL);
g_return_val_if_fail (window == NULL || GDK_IS_DRAWABLE (window), NULL);
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;
for (y = 0; y < height; y++)
{
guchar *dst = impl->data + y * width;
const gchar *src = data + (y * bpl);
for (x = 0; x < width; x++)
{
if ((src[x / 8] >> x % 8) & 1)
*dst = 0xff;
else
*dst = 0;
dst++;
}
}
return pixmap;
}
GdkPixmap*
gdk_pixmap_create_from_data (GdkDrawable *drawable,
const gchar *data,
gint width,
gint height,
gint depth,
const GdkColor *fg,
const GdkColor *bg)
{
/* FIXME: Implement */
return NULL;
}
GdkPixmap *
gdk_pixmap_foreign_new_for_display (GdkDisplay *display,
GdkNativeWindow anid)
{
return NULL;
}
GdkPixmap*
gdk_pixmap_foreign_new (GdkNativeWindow anid)
{
return NULL;
}
GdkPixmap *
gdk_pixmap_foreign_new_for_screen (GdkScreen *screen,
GdkNativeWindow anid,
gint width,
gint height,
gint depth)
{
return NULL;
}
GdkPixmap*
gdk_pixmap_lookup (GdkNativeWindow anid)
{
return NULL;
}
GdkPixmap*
gdk_pixmap_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
return NULL;
}