summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog70
-rw-r--r--ChangeLog.pre-2-070
-rw-r--r--ChangeLog.pre-2-1070
-rw-r--r--ChangeLog.pre-2-270
-rw-r--r--ChangeLog.pre-2-470
-rw-r--r--ChangeLog.pre-2-670
-rw-r--r--ChangeLog.pre-2-870
-rw-r--r--gdk/gdkdraw.c557
-rw-r--r--gdk/gdkdrawable.h25
-rw-r--r--gdk/gdkimage.c263
-rw-r--r--gdk/gdkinternals.h42
-rw-r--r--gdk/gdkpixbuf-drawable.c87
-rw-r--r--gdk/gdkpixbuf-render.c191
-rw-r--r--gdk/gdkpixmap.c69
-rw-r--r--gdk/gdkrgb.c259
-rw-r--r--gdk/gdkwindow.c112
-rw-r--r--gdk/x11/gdkdrawable-x11.c567
-rw-r--r--gdk/x11/gdkgc-x11.c8
-rw-r--r--gdk/x11/gdkimage-x11.c345
-rw-r--r--gdk/x11/gdkpango-x11.c2
-rw-r--r--gdk/x11/gdkprivate-x11.h17
-rw-r--r--tests/testrgb.c48
22 files changed, 2449 insertions, 633 deletions
diff --git a/ChangeLog b/ChangeLog
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 287f5a0f8..be56ec86c 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,73 @@
+Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h
+ (_gdk_x11_have_render): Private function to tell if we have RENDER
+ extension.
+
+ * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return
+ None if we don't have RENDER extension.
+
+ * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't
+ use Xft unless we have render extension.
+
+ * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture):
+ Handle missing render extension.
+
+ * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c
+ gdk/gdkinternals.h: Add a private copy_to_image() virtual function
+ to the GdkDrawable vtable that extends get_image() to allow
+ copying onto existing images. Make the default implementation of
+ get_image() use this so that backends don't have to implement
+ both. Add private wrapper _gdk_drawable_copy_to_image().
+
+ * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c
+ gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement
+ copy_to_image() semantics, speed up by using ShmPixmaps and
+ XCopyArea when possible, XFlush() after ungrabbing the server,
+ generally redo the logic once again.
+
+ * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c
+ _gdk_windowing_bits_per_depth(): Function to convert from depth to
+ bits-per-pixel. (We assume only one bpp per depth - X requires
+ this.)
+
+ * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB
+ scratch image code into a generic _gdk_image_get_scratch() chunk
+ of code that we can use other places we need scratch images.
+
+ * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h:
+ Add _gdk_image_new_for_depth() as the backend
+ to _gdk_image_new() to allowing creating images with
+ a depth and no visual.
+
+ * gdk/gdkpixbuf-drawable.c: Fix so that getting
+ parts of images not at 0,0 actually works.
+
+ * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c
+ gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c:
+ - Add a new GdkDrawableClass vfunc _draw_pixbuf, and
+ _gdk_draw_pixbuf() [ will be made public later ], to allow
+ backends to accelerate drawing pixbufs.
+ - Move the implementation of gdk_pixbuf_render_to_drawable_alpha()
+ to be the default implementation.
+ - Update docs for gdk_pixbuf_render_to_drawable_alpha().
+ - Optimize the default implementation by using
+ _gdk_image_copy_to_pixmap() and scratch shared images, and
+ special casing the compositing.
+
+ * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf()
+ with alpha using the RENDER extension.
+
+ * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable):
+ Optimize by _gdk_image_copy_to_pixmap() and scratch images.
+
+ * tests/testrgb.c: Add test for speed of alpha composition,
+ reduce the number of iterations since alpha composition
+ can be a bit slow.
+
+ * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap):
+ Private function to get a ShmPixmap for an image, if possible.
+
2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers.
diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c
index e2d50121b..c7882c577 100644
--- a/gdk/gdkdraw.c
+++ b/gdk/gdkdraw.c
@@ -27,15 +27,34 @@
#include "gdkdrawable.h"
#include "gdkinternals.h"
#include "gdkwindow.h"
-
-static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height,
- gint *composite_x_offset,
- gint *composite_y_offset);
-static GdkRegion * gdk_drawable_real_get_visible_region (GdkDrawable *drawable);
+#include "gdk-pixbuf-private.h"
+#include "gdkpixbuf.h"
+
+static GdkImage* gdk_drawable_real_get_image (GdkDrawable *drawable,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gint *composite_x_offset,
+ gint *composite_y_offset);
+static GdkRegion * gdk_drawable_real_get_visible_region (GdkDrawable *drawable);
+static void gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither);
static void gdk_drawable_class_init (GdkDrawableClass *klass);
@@ -70,10 +89,12 @@ gdk_drawable_get_type (void)
static void
gdk_drawable_class_init (GdkDrawableClass *klass)
{
+ klass->get_image = gdk_drawable_real_get_image;
klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable;
/* Default implementation for clip and visible region is the same */
klass->get_clip_region = gdk_drawable_real_get_visible_region;
klass->get_visible_region = gdk_drawable_real_get_visible_region;
+ klass->_draw_pixbuf = gdk_drawable_real_draw_pixbuf;
}
/* Manipulation of drawables
@@ -529,6 +550,57 @@ gdk_draw_image (GdkDrawable *drawable,
xdest, ydest, width, height);
}
+/**
+ * _gdk_draw_pixbuf:
+ * @drawable: Destination drawable.
+ * @gc: a #GdkGC, used for clipping, or %NULL
+ * @pixbuf: a #GdkPixbuf
+ * @src_x: Source X coordinate within pixbuf.
+ * @src_y: Source Y coordinates within pixbuf.
+ * @dest_x: Destination X coordinate within drawable.
+ * @dest_y: Destination Y coordinate within drawable.
+ * @width: Width of region to render, in pixels, or -1 to use pixbuf width.
+ * @height: Height of region to render, in pixels, or -1 to use pixbuf height.
+ * @dither: Dithering mode for GdkRGB.
+ * @x_dither: X offset for dither.
+ * @y_dither: Y offset for dither.
+ *
+ * Renders a rectangular portion of a pixbuf to a drawable. The destination
+ * drawable must have a colormap. All windows have a colormap, however, pixmaps
+ * only have colormap by default if they were created with a non-NULL window argument.
+ * Otherwise a colormap must be set on them with gdk_drawable_set_colormap.
+ *
+ * On older X servers, rendering pixbufs with an alpha channel involves round trips
+ * to the X server, and may be somewhat slow.
+ **/
+void
+_gdk_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither)
+{
+ g_return_if_fail (GDK_IS_DRAWABLE (drawable));
+ g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+
+ if (width == -1)
+ width = gdk_pixbuf_get_width (pixbuf);
+ if (height == -1)
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ GDK_DRAWABLE_GET_CLASS (drawable)->_draw_pixbuf (drawable, gc, pixbuf,
+ src_x, src_y, dest_x, dest_y, width, height,
+ dither, x_dither, y_dither);
+}
+
void
gdk_draw_points (GdkDrawable *drawable,
GdkGC *gc,
@@ -618,6 +690,80 @@ gdk_draw_glyphs (GdkDrawable *drawable,
/**
+ * _gdk_drawable_copy_to_image:
+ * @drawable: a #GdkDrawable
+ * @image: a #GdkDrawable, or %NULL if a new @image should be created.
+ * @src_x: x coordinate on @drawable
+ * @src_y: y coordinate on @drawable
+ * @dest_x: x coordinate within @image. Must be 0 if @image is %NULL
+ * @dest_y: y coordinate within @image. Must be 0 if @image is %NULL
+ * @width: width of region to get
+ * @height: height or region to get
+ *
+ * Copies a portion of @drawable into the client side image structure
+ * @image. If @image is %NULL, creates a new image of size @width x @height
+ * and copies into that. See gdk_drawable_get_image() for further details.
+ *
+ * Return value: @image, or a new a #GdkImage containing the contents
+ of @drawable
+ **/
+GdkImage*
+_gdk_drawable_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height)
+{
+ GdkDrawable *composite;
+ gint composite_x_offset = 0;
+ gint composite_y_offset = 0;
+ GdkImage *retval;
+ GdkColormap *cmap;
+
+ g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
+ g_return_val_if_fail (src_x >= 0, NULL);
+ g_return_val_if_fail (src_y >= 0, NULL);
+
+ /* FIXME? Note race condition since we get the size then
+ * get the image, and the size may have changed.
+ */
+
+ if (width < 0 || height < 0)
+ gdk_drawable_get_size (drawable,
+ width < 0 ? &width : NULL,
+ height < 0 ? &height : NULL);
+
+ composite =
+ GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
+ src_x, src_y,
+ width, height,
+ &composite_x_offset,
+ &composite_y_offset);
+
+ retval = GDK_DRAWABLE_GET_CLASS (composite)->_copy_to_image (composite,
+ image,
+ src_x - composite_x_offset,
+ src_y - composite_y_offset,
+ dest_x, dest_y,
+ width, height);
+
+ g_object_unref (G_OBJECT (composite));
+
+ if (!image && retval)
+ {
+ cmap = gdk_drawable_get_colormap (drawable);
+
+ if (cmap)
+ gdk_image_set_colormap (retval, cmap);
+ }
+
+ return retval;
+}
+
+/**
* gdk_drawable_get_image:
* @drawable: a #GdkDrawable
* @x: x coordinate on @drawable
@@ -705,6 +851,16 @@ gdk_drawable_get_image (GdkDrawable *drawable,
return retval;
}
+static GdkImage*
+gdk_drawable_real_get_image (GdkDrawable *drawable,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ return _gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height);
+}
+
static GdkDrawable*
gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
gint x,
@@ -776,3 +932,386 @@ gdk_drawable_real_get_visible_region (GdkDrawable *drawable)
return gdk_region_rectangle (&rect);
}
+
+static void
+composite (guchar *src_buf,
+ gint src_rowstride,
+ guchar *dest_buf,
+ gint dest_rowstride,
+ gint width,
+ gint height)
+{
+ guchar *src = src_buf;
+ guchar *dest = dest_buf;
+
+ while (height--)
+ {
+ gint twidth = width;
+ guchar *p = src;
+ guchar *q = dest;
+
+ while (twidth--)
+ {
+ guchar a = p[3];
+ guint t;
+
+ t = a * p[0] + (255 - a) * q[0] + 0x80;
+ q[0] = (t + (t >> 8)) >> 8;
+ t = a * p[1] + (255 - a) * q[1] + 0x80;
+ q[1] = (t + (t >> 8)) >> 8;
+ t = a * p[2] + (255 - a) * q[2] + 0x80;
+ q[2] = (t + (t >> 8)) >> 8;
+
+ p += 4;
+ q += 3;
+ }
+
+ src += src_rowstride;
+ dest += dest_rowstride;
+ }
+}
+
+static void
+composite_0888 (guchar *src_buf,
+ gint src_rowstride,
+ guchar *dest_buf,
+ gint dest_rowstride,
+ GdkByteOrder dest_byte_order,
+ gint width,
+ gint height)
+{
+ guchar *src = src_buf;
+ guchar *dest = dest_buf;
+
+ while (height--)
+ {
+ gint twidth = width;
+ guchar *p = src;
+ guchar *q = dest;
+
+ if (dest_byte_order == GDK_LSB_FIRST)
+ {
+ while (twidth--)
+ {
+ guint t;
+
+ t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80;
+ q[0] = (t + (t >> 8)) >> 8;
+ t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80;
+ q[1] = (t + (t >> 8)) >> 8;
+ t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80;
+ q[2] = (t + (t >> 8)) >> 8;
+ p += 4;
+ q += 4;
+ }
+ }
+ else
+ {
+ while (twidth--)
+ {
+ guint t;
+
+ t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80;
+ q[1] = (t + (t >> 8)) >> 8;
+ t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80;
+ q[2] = (t + (t >> 8)) >> 8;
+ t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80;
+ q[3] = (t + (t >> 8)) >> 8;
+ p += 4;
+ q += 4;
+ }
+ }
+
+ src += src_rowstride;
+ dest += dest_rowstride;
+ }
+}
+
+static void
+composite_565 (guchar *src_buf,
+ gint src_rowstride,
+ guchar *dest_buf,
+ gint dest_rowstride,
+ GdkByteOrder dest_byte_order,
+ gint width,
+ gint height)
+{
+ guchar *src = src_buf;
+ guchar *dest = dest_buf;
+
+ while (height--)
+ {
+ gint twidth = width;
+ guchar *p = src;
+ gushort *q = (gushort *)dest;
+
+ while (twidth--)
+ {
+ guchar a = p[3];
+ guint tr, tg, tb;
+ guint tr1, tg1, tb1;
+ guint tmp = *q;
+
+#if 1
+ /* This is fast, and corresponds to what composite() above does
+ * if we converted to 8-bit first.
+ */
+ tr = (tmp & 0xf800);
+ tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
+ tg = (tmp & 0x07e0);
+ tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
+ tb = (tmp & 0x001f);
+ tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
+
+ *q = (((tr1 + (tr1 >> 8)) & 0xf800) |
+ (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5) |
+ ((tb1 + (tb1 >> 8)) >> 11));
+#else
+ /* This version correspond to the result we get with XRENDER -
+ * a bit of precision is lost since we convert to 8 bit after premultiplying
+ * instead of at the end
+ */
+ guint tr2, tg2, tb2;
+ guint tr3, tg3, tb3;
+
+ tr = (tmp & 0xf800);
+ tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
+ tr2 = a * p[0] + 0x80;
+ tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8);
+
+ tg = (tmp & 0x07e0);
+ tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
+ tg2 = a * p[0] + 0x80;
+ tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8);
+
+ tb = (tmp & 0x001f);
+ tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
+ tb2 = a * p[0] + 0x80;
+ tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8);
+
+ *q = (((tr3 & 0xf8) << 8) |
+ ((tg3 & 0xfc) << 3) |
+ ((tb3 >> 3)));
+#endif
+
+ p += 4;
+ q++;
+ }
+
+ src += src_rowstride;
+ dest += dest_rowstride;
+ }
+}
+
+static void
+gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither)
+{
+ gboolean free_gc = FALSE;
+ GdkPixbuf *composited = NULL;
+ gint dwidth, dheight;
+ GdkRegion *clip;
+ GdkRegion *drect;
+ GdkRectangle tmp_rect;
+
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+ g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
+ g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
+ g_return_if_fail (pixbuf->bits_per_sample == 8);
+
+ g_return_if_fail (drawable != NULL);
+
+ if (width == -1)
+ width = pixbuf->width;
+ if (height == -1)
+ height = pixbuf->height;
+
+ g_return_if_fail (width >= 0 && height >= 0);
+ g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
+ g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
+
+ /* Clip to the drawable; this is required for get_from_drawable() so
+ * can't be done implicitly
+ */
+
+ if (dest_x < 0)
+ {
+ src_x -= dest_x;
+ width += dest_x;
+ dest_x = 0;
+ }
+
+ if (dest_y < 0)
+ {
+ src_y -= dest_y;
+ height += dest_y;
+ dest_y = 0;
+ }
+
+ gdk_drawable_get_size (drawable, &dwidth, &dheight);
+
+ if ((dest_x + width) > dwidth)
+ width = dwidth - dest_x;
+
+ if ((dest_y + height) > dheight)
+ height = dheight - dest_y;
+
+ if (width <= 0 || height <= 0)
+ return;
+
+ /* Clip to the clip region; this avoids getting more
+ * image data from the server than we need to.
+ */
+
+ tmp_rect.x = dest_x;
+ tmp_rect.y = dest_y;
+ tmp_rect.width = width;
+ tmp_rect.height = height;
+
+ drect = gdk_region_rectangle (&tmp_rect);
+ clip = gdk_drawable_get_clip_region (drawable);
+
+ gdk_region_intersect (drect, clip);
+
+ gdk_region_get_clipbox (drect, &tmp_rect);
+
+ gdk_region_destroy (drect);
+ gdk_region_destroy (clip);
+
+ if (tmp_rect.width == 0 ||
+ tmp_rect.height == 0)
+ return;
+
+ /* Actually draw */
+
+ if (!gc)
+ {
+ gc = gdk_gc_new (drawable);
+ free_gc = TRUE;
+ }
+
+ if (pixbuf->has_alpha)
+ {
+ GdkVisual *visual = gdk_drawable_get_visual (drawable);
+ void (*composite_func) (guchar *src_buf,
+ gint src_rowstride,
+ guchar *dest_buf,
+ gint dest_rowstride,
+ GdkByteOrder dest_byte_order,
+ gint width,
+ gint height) = NULL;
+
+ /* First we see if we have a visual-specific composition function that can composite
+ * the pixbuf data directly onto the image
+ */
+ if (visual)
+ {
+ gint bits_per_pixel = _gdk_windowing_get_bits_for_depth (visual->depth);
+
+ if (visual->byte_order == (G_BYTE_ORDER == G_BIG_ENDIAN ? GDK_MSB_FIRST : GDK_LSB_FIRST) &&
+ visual->depth == 16 &&
+ visual->red_mask == 0xf800 &&
+ visual->green_mask == 0x07e0 &&
+ visual->blue_mask == 0x001f)
+ composite_func = composite_565;
+ else if (visual->depth == 24 && bits_per_pixel == 32 &&
+ visual->red_mask == 0xff0000 &&
+ visual->green_mask == 0x00ff00 &&
+ visual->blue_mask == 0x0000ff)
+ composite_func = composite_0888;
+ }
+
+ /* We can't use our composite func if we are required to dither
+ */
+ if (composite_func && !(dither == GDK_RGB_DITHER_MAX && visual->depth != 24))
+ {
+ gint x0, y0;
+ for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
+ {
+ gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
+ for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
+ {
+ gint xs0, ys0;
+
+ gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
+
+ GdkImage *image = _gdk_image_get_scratch (width1, height1, gdk_drawable_get_depth (drawable), &xs0, &ys0);
+
+ _gdk_drawable_copy_to_image (drawable, image,
+ dest_x + x0, dest_y + y0,
+ xs0, ys0,
+ width1, height1);
+ (*composite_func) (pixbuf->pixels + (src_y + y0) * pixbuf->rowstride + (src_x + x0) * 4,
+ pixbuf->rowstride,
+ image->mem + ys0 * image->bpl + xs0 * image->bpp,
+ image->bpl,
+ visual->byte_order,
+ width1, height1);
+ gdk_draw_image (drawable, gc, image,
+ xs0, ys0,
+ dest_x + x0, dest_y + y0,
+ width1, height1);
+ }
+ }
+
+ goto out;
+ }
+ else
+ {
+ /* No special composition func, convert dest to 24 bit RGB data, composite against
+ * that, and convert back.
+ */
+ composited = gdk_pixbuf_get_from_drawable (NULL,
+ drawable,
+ NULL,
+ dest_x, dest_y,
+ 0, 0,
+ width, height);
+
+ if (composited)
+ composite (pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 4,
+ pixbuf->rowstride,
+ composited->pixels,
+ composited->rowstride,
+ width, height);
+ }
+ }
+
+ if (composited)
+ {
+ gdk_pixbuf_render_to_drawable (composited,
+ drawable, gc,
+ 0, 0,
+ dest_x, dest_y,
+ width, height,
+ dither,
+ x_dither, y_dither);
+ }
+ else
+ {
+ gdk_pixbuf_render_to_drawable (pixbuf,
+ drawable, gc,
+ src_x, src_y,
+ dest_x, dest_y,
+ width, height,
+ dither,
+ x_dither, y_dither);
+ }
+
+ out:
+ if (composited)
+ g_object_unref (G_OBJECT (composited));
+
+ if (free_gc)
+ gdk_gc_unref (gc);
+}
diff --git a/gdk/gdkdrawable.h b/gdk/gdkdrawable.h
index e343d8ae6..6d2d4d9b7 100644
--- a/gdk/gdkdrawable.h
+++ b/gdk/gdkdrawable.h
@@ -3,6 +3,8 @@
#include <gdk/gdktypes.h>
#include <gdk/gdkgc.h>
+#include <gdk/gdkrgb.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#ifdef __cplusplus
extern "C" {
@@ -130,7 +132,28 @@ struct _GdkDrawableClass
gint height,
gint *composite_x_offset,
gint *composite_y_offset);
-
+
+ void (*_draw_pixbuf) (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither);
+ GdkImage* (*_copy_to_image) (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height);
+
void (*_gdk_reserved1) (void);
void (*_gdk_reserved2) (void);
void (*_gdk_reserved3) (void);
diff --git a/gdk/gdkimage.c b/gdk/gdkimage.c
index fe913325f..e748d8f52 100644
--- a/gdk/gdkimage.c
+++ b/gdk/gdkimage.c
@@ -27,8 +27,10 @@
#include <stdlib.h>
#include <sys/types.h>
+#include "gdk.h" /* For gdk_flush() */
#include "gdkimage.h"
#include "gdkprivate.h"
+#include "gdkinternals.h" /* For scratch_image code */
/**
* gdk_image_ref:
@@ -137,3 +139,264 @@ gdk_image_get_colormap (GdkImage *image)
return image->colormap;
}
+
+/* We have N_REGION GDK_SCRATCH_IMAGE_WIDTH x GDK_SCRATCH_IMAGE_HEIGHT regions divided
+ * up between n_images different images. possible_n_images gives
+ * various divisors of N_REGIONS. The reason for allowing this
+ * flexibility is that we want to create as few images as possible,
+ * but we want to deal with the abberant systems that have a SHMMAX
+ * limit less than
+ *
+ * GDK_SCRATCH_IMAGE_WIDTH * GDK_SCRATCH_IMAGE_HEIGHT * N_REGIONS * 4 (384k)
+ *
+ * (Are there any such?)
+ */
+#define N_REGIONS 6
+static const int possible_n_images[] = { 1, 2, 3, 6 };
+
+/* We allocate one GdkScratchImageInfo structure for each
+ * depth where we are allocating scratch images. (Future: one
+ * per depth, per display)
+ */
+typedef struct _GdkScratchImageInfo GdkScratchImageInfo;
+
+struct _GdkScratchImageInfo {
+ gint depth;
+
+ gint n_images;
+ GdkImage *static_image[N_REGIONS];
+ gint static_image_idx;
+
+ /* In order to optimize filling fractions, we simultaneously fill in up
+ * to three regions of size GDK_SCRATCH_IMAGE_WIDTH * GDK_SCRATCH_IMAGE_HEIGHT: one
+ * for images that are taller than GDK_SCRATCH_IMAGE_HEIGHT / 2, and must
+ * be tiled horizontally. One for images that are wider than
+ * GDK_SCRATCH_IMAGE_WIDTH / 2 and must be tiled vertically, and a third
+ * for images smaller than GDK_SCRATCH_IMAGE_HEIGHT / 2 x GDK_SCRATCH_IMAGE_WIDTH x 2
+ * that we tile in horizontal rows.
+ */
+ gint horiz_idx;
+ gint horiz_y;
+ gint vert_idx;
+ gint vert_x;
+
+ /* tile_y1 and tile_y2 define the horizontal band into
+ * which we are tiling images. tile_x is the x extent to
+ * which that is filled
+ */
+ gint tile_idx;
+ gint tile_x;
+ gint tile_y1;
+ gint tile_y2;
+};
+
+static GSList *scratch_image_infos = NULL;
+
+static gboolean
+allocate_scratch_images (GdkScratchImageInfo *info,
+ gint n_images,
+ gboolean shared)
+{
+ gint i;
+
+ for (i = 0; i < n_images; i++)
+ {
+ info->static_image[i] = _gdk_image_new_for_depth (shared ? GDK_IMAGE_SHARED : GDK_IMAGE_NORMAL,
+ NULL,
+ GDK_SCRATCH_IMAGE_WIDTH * (N_REGIONS / n_images), GDK_SCRATCH_IMAGE_HEIGHT,
+ info->depth);
+
+ if (!info->static_image[i])
+ {
+ gint j;
+
+ for (j = 0; j < i; j++)
+ gdk_image_unref (info->static_image[i]);
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+GdkScratchImageInfo *
+scratch_image_info_for_depth (gint depth)
+{
+ GSList *tmp_list;
+ GdkScratchImageInfo *image_info;
+ gint i;
+
+ tmp_list = scratch_image_infos;
+ while (tmp_list)
+ {
+ image_info = tmp_list->data;
+ if (image_info->depth == depth)
+ return image_info;
+
+ tmp_list = tmp_list->next;
+ }
+
+ image_info = g_new (GdkScratchImageInfo, 1);
+
+ image_info->depth = depth;
+
+ /* Try to allocate as few possible shared images */
+ for (i=0; i < G_N_ELEMENTS (possible_n_images); i++)
+ {
+ if (allocate_scratch_images (image_info, possible_n_images[i], TRUE))
+ {
+ image_info->n_images = possible_n_images[i];
+ break;
+ }
+ }
+
+ /* If that fails, just allocate N_REGIONS normal images */
+ if (i == G_N_ELEMENTS (possible_n_images))
+ {
+ allocate_scratch_images (image_info, N_REGIONS, FALSE);
+ image_info->n_images = N_REGIONS;
+ }
+
+ image_info->static_image_idx = 0;
+
+ image_info->horiz_y = GDK_SCRATCH_IMAGE_HEIGHT;
+ image_info->vert_x = GDK_SCRATCH_IMAGE_WIDTH;
+ image_info->tile_x = GDK_SCRATCH_IMAGE_WIDTH;
+ image_info->tile_y1 = image_info->tile_y2 = GDK_SCRATCH_IMAGE_HEIGHT;
+
+ scratch_image_infos = g_slist_prepend (scratch_image_infos, image_info);
+
+ return image_info;
+}
+
+/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
+ for performance evaluation. */
+
+#undef NO_FLUSH
+
+#ifdef VERBOSE
+static gint sincelast;
+#endif
+
+static gint
+alloc_scratch_image (GdkScratchImageInfo *image_info)
+{
+ if (image_info->static_image_idx == N_REGIONS)
+ {
+#ifndef NO_FLUSH
+ gdk_flush ();
+#endif
+#ifdef VERBOSE
+ g_print ("flush, %d puts since last flush\n", sincelast);
+ sincelast = 0;
+#endif
+ image_info->static_image_idx = 0;
+
+ /* Mark all regions that we might be filling in as completely
+ * full, to force new tiles to be allocated for subsequent
+ * images
+ */
+ image_info->horiz_y = GDK_SCRATCH_IMAGE_HEIGHT;
+ image_info->vert_x = GDK_SCRATCH_IMAGE_WIDTH;
+ image_info->tile_x = GDK_SCRATCH_IMAGE_WIDTH;
+ image_info->tile_y1 = image_info->tile_y2 = GDK_SCRATCH_IMAGE_HEIGHT;
+ }
+ return image_info->static_image_idx++;
+}
+
+/**
+ * _gdk_image_get_scratch:
+ * @width: desired width
+ * @height: desired height
+ * @depth: depth of image
+ * @x: X location within returned image of scratch image
+ * @y: Y location within returned image of scratch image
+ *
+ * Allocates an image of size width/height, up to a maximum
+ * of GDK_SCRATCH_IMAGE_WIDTHxGDK_SCRATCH_IMAGE_HEIGHT
+ *
+ * Return value: a scratch image. This must be used by a
+ * call to gdk_image_put() before any other calls to
+ * _gdk_image_get_scratch()
+ **/
+GdkImage *
+_gdk_image_get_scratch (gint width,
+ gint height,
+ gint depth,
+ gint *x,
+ gint *y)
+{
+ GdkScratchImageInfo *image_info;
+ GdkImage *image;
+ gint idx;
+
+ image_info = scratch_image_info_for_depth (depth);
+
+ if (width >= (GDK_SCRATCH_IMAGE_WIDTH >> 1))
+ {
+ if (height >= (GDK_SCRATCH_IMAGE_HEIGHT >> 1))
+ {
+ idx = alloc_scratch_image (image_info);
+ *x = 0;
+ *y = 0;
+ }
+ else
+ {
+ if (height + image_info->horiz_y > GDK_SCRATCH_IMAGE_HEIGHT)
+ {
+ image_info->horiz_idx = alloc_scratch_image (image_info);
+ image_info->horiz_y = 0;
+ }
+ idx = image_info->horiz_idx;
+ *x = 0;
+ *y = image_info->horiz_y;
+ image_info->horiz_y += height;
+ }
+ }
+ else
+ {
+ if (height >= (GDK_SCRATCH_IMAGE_HEIGHT >> 1))
+ {
+ if (width + image_info->vert_x > GDK_SCRATCH_IMAGE_WIDTH)
+ {
+ image_info->vert_idx = alloc_scratch_image (image_info);
+ image_info->vert_x = 0;
+ }
+ idx = image_info->vert_idx;
+ *x = image_info->vert_x;
+ *y = 0;
+ /* using 3 and -4 would be slightly more efficient on 32-bit machines
+ with > 1bpp displays */
+ image_info->vert_x += (width + 7) & -8;
+ }
+ else
+ {
+ if (width + image_info->tile_x > GDK_SCRATCH_IMAGE_WIDTH)
+ {
+ image_info->tile_y1 = image_info->tile_y2;
+ image_info->tile_x = 0;
+ }
+ if (height + image_info->tile_y1 > GDK_SCRATCH_IMAGE_HEIGHT)
+ {
+ image_info->tile_idx = alloc_scratch_image (image_info);
+ image_info->tile_x = 0;
+ image_info->tile_y1 = 0;
+ image_info->tile_y2 = 0;
+ }
+ if (height + image_info->tile_y1 > image_info->tile_y2)
+ image_info->tile_y2 = height + image_info->tile_y1;
+ idx = image_info->tile_idx;
+ *x = image_info->tile_x;
+ *y = image_info->tile_y1;
+ image_info->tile_x += (width + 7) & -8;
+ }
+ }
+ image = image_info->static_image[idx * image_info->n_images / N_REGIONS];
+ *x += GDK_SCRATCH_IMAGE_WIDTH * (idx % (N_REGIONS / image_info->n_images));
+#ifdef VERBOSE
+ g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x, *y, width, height);
+ sincelast++;
+#endif
+ return image;
+}
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index aa557abd5..327d56560 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -158,6 +158,43 @@ void _gdk_event_queue_append (GdkEvent *event);
void _gdk_event_button_generate (GdkEvent *event);
+#define GDK_SCRATCH_IMAGE_WIDTH 256
+#define GDK_SCRATCH_IMAGE_HEIGHT 64
+
+GdkImage* _gdk_image_new_for_depth (GdkImageType type,
+ GdkVisual *visual,
+ gint width,
+ gint height,
+ gint depth);
+GdkImage *_gdk_image_get_scratch (gint width,
+ gint height,
+ gint depth,
+ gint *x,
+ gint *y);
+
+/* Will most likely be exported in the future
+ */
+void _gdk_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither);
+GdkImage *_gdk_drawable_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height);
+
/*************************************
* Interfaces used by windowing code *
*************************************/
@@ -204,6 +241,11 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkWindow *window,
gint *y,
GdkModifierType *mask);
+/* Return the number of bits-per-pixel for images of the specified depth.
+ * (Future: needs to be GdkDiplay specific.)
+ */
+gint _gdk_windowing_get_bits_for_depth (gint depth);
+
#define GDK_WINDOW_IS_MAPPED(window) ((((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0)
/* Called before processing updates for a window. This gives the windowing
diff --git a/gdk/gdkpixbuf-drawable.c b/gdk/gdkpixbuf-drawable.c
index f4a99cab7..bfb0d941d 100644
--- a/gdk/gdkpixbuf-drawable.c
+++ b/gdk/gdkpixbuf-drawable.c
@@ -72,7 +72,7 @@ bitmap1 (GdkImage *image,
int bpl;
register guint8 data;
guint8 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("bitmap, no alpha\n"));
@@ -128,7 +128,7 @@ bitmap1a (GdkImage *image,
int bpl;
register guint8 data;
guint8 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("bitmap, with alpha\n"));
@@ -183,7 +183,7 @@ rgb1 (GdkImage *image,
int bpl;
register guint8 data;
guint8 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("1 bits/pixel\n"));
@@ -231,7 +231,7 @@ rgb1a (GdkImage *image,
int bpl;
register guint8 data;
guint8 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("1 bits/pixel\n"));
@@ -279,7 +279,7 @@ rgb8 (GdkImage *image,
int bpl;
guint32 mask;
register guint32 data;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
register guint8 *s;
register guint8 *o;
@@ -326,7 +326,7 @@ rgb8a (GdkImage *image,
guint32 remap[256];
register guint8 *s; /* read 2 pixels at once */
register guint32 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -387,7 +387,7 @@ rgb565lsb (GdkImage *image,
register guint8 *s; /* read 2 pixels at once */
#endif
register guint16 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -490,7 +490,7 @@ rgb565msb (GdkImage *image,
register guint32 *s; /* read 2 pixels at once */
#endif
register guint16 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -596,7 +596,7 @@ rgb565alsb (GdkImage *image,
#endif
register guint32 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -659,7 +659,7 @@ rgb565amsb (GdkImage *image,
#endif
register guint32 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -717,7 +717,7 @@ rgb555lsb (GdkImage *image,
register guint8 *s; /* read 2 pixels at once */
#endif
register guint16 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -821,7 +821,7 @@ rgb555msb (GdkImage *image,
register guint32 *s; /* read 2 pixels at once */
#endif
register guint16 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -922,7 +922,7 @@ rgb555alsb (GdkImage *image,
#endif
register guint32 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -985,7 +985,7 @@ rgb555amsb (GdkImage *image,
#endif
register guint32 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -1039,7 +1039,7 @@ rgb888alsb (GdkImage *image,
guint8 *s; /* for byte order swapping */
guint8 *o;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl;
@@ -1076,7 +1076,7 @@ rgb888lsb (GdkImage *image,
int xx, yy;
int bpl;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
guint8 *o, *s;
bpl = image->bpl;
@@ -1112,7 +1112,7 @@ rgb888amsb (GdkImage *image,
int xx, yy;
int bpl;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
#ifdef LITTLE
guint32 *o;
guint32 *s;
@@ -1166,7 +1166,7 @@ rgb888msb (GdkImage *image,
int xx, yy;
int bpl;
- guint8 *srow = image->mem, *orow = pixels;
+ guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
guint8 *s;
guint8 *o;
@@ -1207,8 +1207,7 @@ convert_real_slow (GdkImage *image,
{
int xx, yy;
int bpl;
- guint8 *srow = image->mem, *orow = pixels;
- guint8 *s;
+ guint8 *orow = pixels;
guint8 *o;
guint32 pixel;
GdkVisual *v;
@@ -1225,7 +1224,6 @@ convert_real_slow (GdkImage *image,
for (yy = y1; yy < y2; yy++)
{
- s = srow;
o = orow;
for (xx = x1; xx < x2; xx++)
{
@@ -1268,7 +1266,6 @@ convert_real_slow (GdkImage *image,
if (alpha)
*o++ = 0xff;
}
- srow += bpl;
orow += rowstride;
}
}
@@ -1481,6 +1478,7 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
int src_width, src_height;
GdkImage *image;
int depth;
+ int x0, y0;
/* General sanity checks */
@@ -1503,6 +1501,14 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
}
+ /* Create the pixbuf if needed */
+ if (!dest)
+ {
+ dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
+ if (dest == NULL)
+ return NULL;
+ }
+
if (cmap == NULL)
cmap = gdk_drawable_get_colormap (src);
@@ -1536,19 +1542,28 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
g_return_val_if_fail (dest_x + width <= dest->width, NULL);
g_return_val_if_fail (dest_y + height <= dest->height, NULL);
}
-
- /* Get Image in ZPixmap format (packed bits). */
- image = gdk_image_get (src, src_x, src_y, width, height);
-
- if (image == NULL)
- return NULL;
-
- dest = gdk_pixbuf_get_from_image (dest, image, cmap,
- 0, 0, dest_x, dest_y,
- width, height);
-
- gdk_image_destroy (image);
+ for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
+ {
+ gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
+ for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
+ {
+ gint xs0, ys0;
+
+ gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
+
+ image = _gdk_image_get_scratch (width1, height1, depth, &xs0, &ys0);
+
+ _gdk_drawable_copy_to_image (src, image,
+ src_x + x0, src_y + y0,
+ xs0, ys0, width1, height1);
+
+ gdk_pixbuf_get_from_image (dest, image, cmap,
+ xs0, ys0, dest_x + x0, dest_y + y0,
+ width1, height1);
+ }
+ }
+
return dest;
}
@@ -1638,8 +1653,8 @@ gdk_pixbuf_get_from_image (GdkPixbuf *dest,
rowstride,
alpha,
src_x, src_y,
- src_x + width,
- src_y + height,
+ width,
+ height,
cmap);
return dest;
diff --git a/gdk/gdkpixbuf-render.c b/gdk/gdkpixbuf-render.c
index 23c75121b..daaf6b31b 100644
--- a/gdk/gdkpixbuf-render.c
+++ b/gdk/gdkpixbuf-render.c
@@ -237,30 +237,19 @@ gdk_pixbuf_render_to_drawable (GdkPixbuf *pixbuf,
* @dest_y: Destination Y coordinate within drawable.
* @width: Width of region to render, in pixels, or -1 to use pixbuf width.
* @height: Height of region to render, in pixels, or -1 to use pixbuf height.
- * @alpha_mode: If the image does not have opacity information, this is ignored.
- * Otherwise, specifies how to handle transparency when rendering.
- * @alpha_threshold: If the image does have opacity information and @alpha_mode
- * is GDK_PIXBUF_ALPHA_BILEVEL, specifies the threshold value for opacity
- * values.
+ * @alpha_mode: Ignored. Present for backwards compatibility.
+ * @alpha_threshold: Ignored. Present for backwards compatibility
* @dither: Dithering mode for GdkRGB.
* @x_dither: X offset for dither.
* @y_dither: Y offset for dither.
*
- * Renders a rectangular portion of a pixbuf to a drawable. This is done using
- * GdkRGB, so the specified drawable must have the GdkRGB visual and colormap.
+ * Renders a rectangular portion of a pixbuf to a drawable. The destination
+ * drawable must have a colormap. All windows have a colormap, however, pixmaps
+ * only have colormap by default if they were created with a non-NULL window argument.
+ * Otherwise a colormap must be set on them with gdk_drawable_set_colormap.
*
- * When used with #GDK_PIXBUF_ALPHA_BILEVEL, this function has to create a bitmap
- * out of the thresholded alpha channel of the image and, it has to set this
- * bitmap as the clipping mask for the GC used for drawing. This can be a
- * significant performance penalty depending on the size and the complexity of
- * the alpha channel of the image. If performance is crucial, consider handling
- * the alpha channel yourself (possibly by caching it in your application) and
- * using gdk_pixbuf_render_to_drawable() or GdkRGB directly instead.
- *
- * The #GDK_PIXBUF_ALPHA_FULL mode involves round trips to the X
- * server, and may also be somewhat slow in its current implementation
- * (though in the future it could be made significantly faster, in
- * principle).
+ * On older X servers, rendering pixbufs with an alpha channel involves round trips
+ * to the X server, and may be somewhat slow.
**/
void
gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf,
@@ -273,165 +262,9 @@ gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf,
GdkRgbDither dither,
int x_dither, int y_dither)
{
- GdkBitmap *bitmap = NULL;
- GdkGC *gc;
- GdkPixbuf *composited = NULL;
- gint dwidth, dheight;
- GdkRegion *clip;
- GdkRegion *drect;
- GdkRectangle tmp_rect;
-
- g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
- g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
- g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
- g_return_if_fail (pixbuf->bits_per_sample == 8);
-
- g_return_if_fail (drawable != NULL);
-
- if (width == -1)
- width = pixbuf->width;
- if (height == -1)
- height = pixbuf->height;
-
- g_return_if_fail (width >= 0 && height >= 0);
- g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
- g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
-
- /* Clip to the drawable; this is required for get_from_drawable() so
- * can't be done implicitly
- */
-
- if (dest_x < 0)
- {
- src_x -= dest_x;
- width += dest_x;
- dest_x = 0;
- }
-
- if (dest_y < 0)
- {
- src_y -= dest_y;
- height += dest_y;
- dest_y = 0;
- }
-
- gdk_drawable_get_size (drawable, &dwidth, &dheight);
-
- if ((dest_x + width) > dwidth)
- width = dwidth - dest_x;
-
- if ((dest_y + height) > dheight)
- height = dheight - dest_y;
-
- if (width <= 0 || height <= 0)
- return;
-
- /* Clip to the clip region; this avoids getting more
- * image data from the server than we need to.
- */
-
- tmp_rect.x = dest_x;
- tmp_rect.y = dest_y;
- tmp_rect.width = width;
- tmp_rect.height = height;
-
- drect = gdk_region_rectangle (&tmp_rect);
- clip = gdk_drawable_get_clip_region (drawable);
-
- gdk_region_intersect (drect, clip);
-
- gdk_region_get_clipbox (drect, &tmp_rect);
-
- gdk_region_destroy (drect);
- gdk_region_destroy (clip);
-
- if (tmp_rect.width == 0 ||
- tmp_rect.height == 0)
- return;
-
- /* Actually draw */
-
- gc = gdk_gc_new (drawable);
-
- if (pixbuf->has_alpha)
- {
- if (alpha_mode == GDK_PIXBUF_ALPHA_FULL)
- {
- GdkPixbuf *sub = NULL;
-
- composited = gdk_pixbuf_get_from_drawable (NULL,
- drawable,
- NULL,
- dest_x, dest_y,
- 0, 0,
- width, height);
-
- if (composited)
- {
- if (src_x != 0 || src_y != 0)
- {
- sub = gdk_pixbuf_new_subpixbuf (pixbuf, src_x, src_y,
- width, height);
- }
-
- gdk_pixbuf_composite (sub ? sub : pixbuf,
- composited,
- 0, 0,
- width, height,
- 0, 0,
- 1.0, 1.0,
- GDK_INTERP_BILINEAR,
- 255);
-
- if (sub)
- g_object_unref (G_OBJECT (sub));
- }
- else
- alpha_mode = GDK_PIXBUF_ALPHA_BILEVEL; /* fall back */
- }
-
- if (alpha_mode == GDK_PIXBUF_ALPHA_BILEVEL)
- {
- bitmap = gdk_pixmap_new (NULL, width, height, 1);
- gdk_pixbuf_render_threshold_alpha (pixbuf, bitmap,
- src_x, src_y,
- 0, 0,
- width, height,
- alpha_threshold);
-
- gdk_gc_set_clip_mask (gc, bitmap);
- gdk_gc_set_clip_origin (gc, dest_x, dest_y);
- }
- }
-
- if (composited)
- {
- gdk_pixbuf_render_to_drawable (composited,
- drawable, gc,
- 0, 0,
- dest_x, dest_y,
- width, height,
- dither,
- x_dither, y_dither);
- }
- else
- {
- gdk_pixbuf_render_to_drawable (pixbuf,
- drawable, gc,
- src_x, src_y,
- dest_x, dest_y,
- width, height,
- dither,
- x_dither, y_dither);
- }
-
- if (bitmap)
- gdk_bitmap_unref (bitmap);
-
- if (composited)
- g_object_unref (G_OBJECT (composited));
-
- gdk_gc_unref (gc);
+ _gdk_draw_pixbuf (drawable, NULL, pixbuf,
+ src_x, src_y, dest_x, dest_y, width, height,
+ dither, x_dither, y_dither);
}
/**
@@ -531,5 +364,3 @@ gdk_pixbuf_render_pixmap_and_mask_for_colormap (GdkPixbuf *pixbuf,
*mask_return = NULL;
}
}
-
-
diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c
index 088e181a5..5e757246f 100644
--- a/gdk/gdkpixmap.c
+++ b/gdk/gdkpixmap.c
@@ -102,16 +102,32 @@ static void gdk_pixmap_draw_image (GdkDrawable *drawable,
gint ydest,
gint width,
gint height);
+static void gdk_pixmap_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither);
+
static void gdk_pixmap_real_get_size (GdkDrawable *drawable,
gint *width,
gint *height);
-static GdkImage* gdk_pixmap_get_image (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height);
+static GdkImage* gdk_pixmap_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height);
static GdkVisual* gdk_pixmap_real_get_visual (GdkDrawable *drawable);
static gint gdk_pixmap_real_get_depth (GdkDrawable *drawable);
@@ -182,12 +198,13 @@ gdk_pixmap_class_init (GdkPixmapObjectClass *klass)
drawable_class->draw_lines = gdk_pixmap_draw_lines;
drawable_class->draw_glyphs = gdk_pixmap_draw_glyphs;
drawable_class->draw_image = gdk_pixmap_draw_image;
+ drawable_class->_draw_pixbuf = gdk_pixmap_draw_pixbuf;
drawable_class->get_depth = gdk_pixmap_real_get_depth;
drawable_class->get_size = gdk_pixmap_real_get_size;
drawable_class->set_colormap = gdk_pixmap_real_set_colormap;
drawable_class->get_colormap = gdk_pixmap_real_get_colormap;
drawable_class->get_visual = gdk_pixmap_real_get_visual;
- drawable_class->get_image = gdk_pixmap_get_image;
+ drawable_class->_copy_to_image = gdk_pixmap_copy_to_image;
}
static void
@@ -367,6 +384,27 @@ gdk_pixmap_draw_image (GdkDrawable *drawable,
}
static void
+gdk_pixmap_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither)
+{
+ GdkPixmapObject *private = (GdkPixmapObject *)drawable;
+
+ _gdk_draw_pixbuf (private->impl, gc, pixbuf,
+ src_x, src_y, dest_x, dest_y, width, height,
+ dither, x_dither, y_dither);
+}
+
+static void
gdk_pixmap_real_get_size (GdkDrawable *drawable,
gint *width,
gint *height)
@@ -418,16 +456,21 @@ gdk_pixmap_real_get_colormap (GdkDrawable *drawable)
}
static GdkImage*
-gdk_pixmap_get_image (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height)
+gdk_pixmap_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height)
{
g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL);
- return gdk_drawable_get_image (((GdkPixmapObject*)drawable)->impl,
- x, y, width, height);
+ return _gdk_drawable_copy_to_image (((GdkPixmapObject*)drawable)->impl,
+ image,
+ src_x, src_y, dest_x, dest_y,
+ width, height);
}
static GdkBitmap *
diff --git a/gdk/gdkrgb.c b/gdk/gdkrgb.c
index d7ce391cd..042d4ca33 100644
--- a/gdk/gdkrgb.c
+++ b/gdk/gdkrgb.c
@@ -46,22 +46,10 @@
#define ENABLE_GRAYSCALE
-#ifdef GDK_RGB_STANDALONE
-
-/* Compiling as a standalone module (i.e. with Gtk 1.0) */
-/* gtk/gtk.h is already included in gdkrgbstub.c */
-#include "config.h"
-#include <gdk/gdkprivate.h>
-
-#else
-
-/* Compiling as a part of Gtk 1.1 or later */
#include "config.h"
#include "gdkprivate.h"
+#include "gdkinternals.h" /* _gdk_windowing_get_bits_for_depth() */
-#endif
-
-#include "gdk.h" /* For gdk_flush() */
#include "gdkrgb.h"
typedef struct _GdkRgbInfo GdkRgbInfo;
@@ -84,30 +72,10 @@ static const gchar* visual_names[] =
"direct color",
};
-#define REGION_WIDTH 256
-#define STAGE_ROWSTRIDE (REGION_WIDTH * 3)
-#define REGION_HEIGHT 64
+#define STAGE_ROWSTRIDE (GDK_SCRATCH_IMAGE_WIDTH * 3)
-/* We have N_REGION REGION_WIDTH x REGION_HEIGHT regions divided
- * up between n_images different images. possible_n_images gives
- * various divisors of N_REGIONS. The reason for allowing this
- * flexibility is that we want to create as few images as possible,
- * but we want to deal with the abberant systems that have a SHMMAX
- * limit less than
- *
- * REGION_WIDTH * REGION_HEIGHT * N_REGIONS * 4 (384k)
- *
- * (Are there any such?)
+/* Some of these fields should go, as they're not being used at all. (?)
*/
-#define N_REGIONS 6
-static const int possible_n_images[] = { 1, 2, 3, 6 };
-
-/* Some of these fields should go, as they're not being used at all.
- Globals should generally migrate into here - it's very likely that
- we'll want to run more than one GdkRgbInfo context at the same time
- (i.e. some but not all windows have privately installed
- colormaps). */
-
struct _GdkRgbInfo
{
GdkVisual *visual;
@@ -147,32 +115,6 @@ struct _GdkRgbInfo
GdkRgbConvFunc conv_indexed;
GdkRgbConvFunc conv_indexed_d;
- gint n_images;
- GdkImage *static_image[N_REGIONS];
- gint static_image_idx;
-
- /* In order to optimize filling fractions, we simultaneously fill in up
- * to three regions of size REGION_WIDTH * REGION_HEIGHT: one
- * for images that are taller than REGION_HEIGHT / 2, and must
- * be tiled horizontally. One for images that are wider than
- * REGION_WIDTH / 2 and must be tiled vertically, and a third
- * for images smaller than REGION_HEIGHT / 2 x REGION_WIDTH x 2
- * that we tile in horizontal rows.
- */
- gint horiz_idx;
- gint horiz_y;
- gint vert_idx;
- gint vert_x;
-
- /* tile_y1 and tile_y2 define the horizontal band into
- * which we are tiling images. tile_x is the x extent to
- * which that is filled
- */
- gint tile_idx;
- gint tile_x;
- gint tile_y1;
- gint tile_y2;
-
guchar *colorcube;
guchar *colorcube_d;
@@ -562,7 +504,7 @@ gdk_rgb_choose_visual (void)
return best_visual;
}
-static void gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image);
+static void gdk_rgb_select_conv (GdkRgbInfo *image_info);
static void
gdk_rgb_set_gray_cmap (GdkRgbInfo *image_info,
@@ -606,39 +548,10 @@ gdk_rgb_set_gray_cmap (GdkRgbInfo *image_info,
}
}
-static gboolean
-gdk_rgb_allocate_images (GdkRgbInfo *image_info,
- gint n_images,
- gboolean shared)
-{
- gint i;
-
- for (i = 0; i < n_images; i++)
- {
- image_info->static_image[i] = gdk_image_new (shared ? GDK_IMAGE_SHARED : GDK_IMAGE_NORMAL,
- image_info->visual,
- REGION_WIDTH * (N_REGIONS / n_images), REGION_HEIGHT);
-
- if (!image_info->static_image[i])
- {
- gint j;
-
- for (j = 0; j < i; j++)
- gdk_image_unref (image_info->static_image[i]);
-
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
static void
gdk_rgb_free_info (GdkRgbInfo *image_info)
{
- gint i;
GSList *tmp_list;
-
if (image_info->stage_buf)
g_free (image_info->stage_buf);
@@ -649,9 +562,6 @@ gdk_rgb_free_info (GdkRgbInfo *image_info)
if (image_info->own_gc)
gdk_gc_unref (image_info->own_gc);
- for (i = 0; i < image_info->n_images; i++)
- gdk_image_unref (image_info->static_image[i]);
-
if (image_info->colorcube)
g_free (image_info->colorcube);
@@ -679,7 +589,6 @@ static GdkRgbInfo *
gdk_rgb_create_info (GdkVisual *visual, GdkColormap *colormap)
{
GdkRgbInfo *image_info;
- gint i;
image_info = g_new0 (GdkRgbInfo, 1);
@@ -765,33 +674,9 @@ gdk_rgb_create_info (GdkVisual *visual, GdkColormap *colormap)
image_info->bitmap = (image_info->visual->depth == 1);
- /* Try to allocate as few possible shared images */
- for (i=0; i < G_N_ELEMENTS (possible_n_images); i++)
- {
- if (gdk_rgb_allocate_images (image_info, possible_n_images[i], TRUE))
- {
- image_info->n_images = possible_n_images[i];
- break;
- }
- }
-
- /* If that fails, just allocate N_REGIONS normal images */
- if (i == G_N_ELEMENTS (possible_n_images))
- {
- gdk_rgb_allocate_images (image_info, N_REGIONS, FALSE);
- image_info->n_images = N_REGIONS;
- }
+ image_info->bpp = (_gdk_windowing_get_bits_for_depth (image_info->visual->depth) + 7) / 8;
- image_info->bpp = image_info->static_image[0]->bpp;
-
- image_info->static_image_idx = 0;
-
- image_info->horiz_y = REGION_HEIGHT;
- image_info->vert_x = REGION_WIDTH;
- image_info->tile_x = REGION_WIDTH;
- image_info->tile_y1 = image_info->tile_y2 = REGION_HEIGHT;
-
- gdk_rgb_select_conv (image_info, image_info->static_image[0]);
+ gdk_rgb_select_conv (image_info);
if (!gdk_rgb_quark)
gdk_rgb_quark = g_quark_from_static_string (gdk_rgb_key);
@@ -1415,7 +1300,7 @@ gdk_rgb_convert_gray8_gray (GdkRgbInfo *image_info, GdkImage *image,
#ifdef HAIRY_CONVERT_565
/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
This assumes native byte ordering - what should really be done is to
- check whether static_image->byte_order is consistent with the _ENDIAN
+ check whether the the image byte_order is consistent with the _ENDIAN
config flag, and if not, use a different function.
This one is even faster than the one below - its inner loop loads 3
@@ -1499,7 +1384,7 @@ gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image,
#else
/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
This assumes native byte ordering - what should really be done is to
- check whether static_image->byte_order is consistent with the _ENDIAN
+ check whether the image byte_order is consistent with the _ENDIAN
config flag, and if not, use a different function.
This routine is faster than the one included with Gtk 1.0 for a number
@@ -2670,7 +2555,7 @@ static guchar *
gdk_rgb_ensure_stage (GdkRgbInfo *image_info)
{
if (image_info->stage_buf == NULL)
- image_info->stage_buf = g_malloc (REGION_HEIGHT * STAGE_ROWSTRIDE);
+ image_info->stage_buf = g_malloc (GDK_SCRATCH_IMAGE_HEIGHT * STAGE_ROWSTRIDE);
return image_info->stage_buf;
}
@@ -2873,7 +2758,7 @@ gdk_rgb_convert_indexed_generic_d (GdkRgbInfo *image_info, GdkImage *image,
/* Select a conversion function based on the visual and a
representative image. */
static void
-gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image)
+gdk_rgb_select_conv (GdkRgbInfo *image_info)
{
GdkByteOrder byte_order;
gint depth, bpp, byterev;
@@ -2887,9 +2772,9 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image)
depth = image_info->visual->depth;
- bpp = image->bits_per_pixel;
+ bpp = _gdk_windowing_get_bits_for_depth (image_info->visual->depth);
- byte_order = image->byte_order;
+ byte_order = image_info->visual->byte_order;
if (gdk_rgb_verbose)
g_print ("Chose visual type=%s depth=%d, image bpp=%d, %s first\n",
visual_names[image_info->visual->type], image_info->visual->depth,
@@ -3066,116 +2951,6 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image)
image_info->conv_indexed_d = conv_indexed_d;
}
-#ifdef VERBOSE
-static gint sincelast;
-#endif
-
-/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
- for performance evaluation. */
-
-#undef NO_FLUSH
-
-static gint
-gdk_rgb_alloc_scratch_image (GdkRgbInfo *image_info)
-{
- if (image_info->static_image_idx == N_REGIONS)
- {
-#ifndef NO_FLUSH
- gdk_flush ();
-#endif
-#ifdef VERBOSE
- g_print ("flush, %d puts since last flush\n", sincelast);
- sincelast = 0;
-#endif
- image_info->static_image_idx = 0;
-
- /* Mark all regions that we might be filling in as completely
- * full, to force new tiles to be allocated for subsequent
- * images
- */
- image_info->horiz_y = REGION_HEIGHT;
- image_info->vert_x = REGION_WIDTH;
- image_info->tile_x = REGION_WIDTH;
- image_info->tile_y1 = image_info->tile_y2 = REGION_HEIGHT;
- }
- return image_info->static_image_idx++;
-}
-
-static GdkImage *
-gdk_rgb_alloc_scratch (GdkRgbInfo *image_info,
- gint width, gint height, gint *x0, gint *y0)
-{
- GdkImage *image;
- gint idx;
-
- if (width >= (REGION_WIDTH >> 1))
- {
- if (height >= (REGION_HEIGHT >> 1))
- {
- idx = gdk_rgb_alloc_scratch_image (image_info);
- *x0 = 0;
- *y0 = 0;
- }
- else
- {
- if (height + image_info->horiz_y > REGION_HEIGHT)
- {
- image_info->horiz_idx = gdk_rgb_alloc_scratch_image (image_info);
- image_info->horiz_y = 0;
- }
- idx = image_info->horiz_idx;
- *x0 = 0;
- *y0 = image_info->horiz_y;
- image_info->horiz_y += height;
- }
- }
- else
- {
- if (height >= (REGION_HEIGHT >> 1))
- {
- if (width + image_info->vert_x > REGION_WIDTH)
- {
- image_info->vert_idx = gdk_rgb_alloc_scratch_image (image_info);
- image_info->vert_x = 0;
- }
- idx = image_info->vert_idx;
- *x0 = image_info->vert_x;
- *y0 = 0;
- /* using 3 and -4 would be slightly more efficient on 32-bit machines
- with > 1bpp displays */
- image_info->vert_x += (width + 7) & -8;
- }
- else
- {
- if (width + image_info->tile_x > REGION_WIDTH)
- {
- image_info->tile_y1 = image_info->tile_y2;
- image_info->tile_x = 0;
- }
- if (height + image_info->tile_y1 > REGION_HEIGHT)
- {
- image_info->tile_idx = gdk_rgb_alloc_scratch_image (image_info);
- image_info->tile_x = 0;
- image_info->tile_y1 = 0;
- image_info->tile_y2 = 0;
- }
- if (height + image_info->tile_y1 > image_info->tile_y2)
- image_info->tile_y2 = height + image_info->tile_y1;
- idx = image_info->tile_idx;
- *x0 = image_info->tile_x;
- *y0 = image_info->tile_y1;
- image_info->tile_x += (width + 7) & -8;
- }
- }
- image = image_info->static_image[idx * image_info->n_images / N_REGIONS];
- *x0 += REGION_WIDTH * (idx % (N_REGIONS / image_info->n_images));
-#ifdef VERBOSE
- g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x0, *y0, width, height);
- sincelast++;
-#endif
- return image;
-}
-
static void
gdk_draw_rgb_image_core (GdkRgbInfo *image_info,
GdkDrawable *drawable,
@@ -3212,15 +2987,15 @@ gdk_draw_rgb_image_core (GdkRgbInfo *image_info,
}
gc = image_info->own_gc;
}
- for (y0 = 0; y0 < height; y0 += REGION_HEIGHT)
+ for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
{
- height1 = MIN (height - y0, REGION_HEIGHT);
- for (x0 = 0; x0 < width; x0 += REGION_WIDTH)
+ height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
+ for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
{
- width1 = MIN (width - x0, REGION_WIDTH);
+ width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
buf_ptr = buf + y0 * rowstride + x0 * pixstride;
- image = gdk_rgb_alloc_scratch (image_info, width1, height1, &xs0, &ys0);
+ image = _gdk_image_get_scratch (width1, height1, image_info->visual->depth, &xs0, &ys0);
conv (image_info, image, xs0, ys0, width1, height1, buf_ptr, rowstride,
x + x0 + xdith, y + y0 + ydith, cmap);
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 28c2b26fe..ea9fdc2b2 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -126,12 +126,27 @@ static void gdk_window_draw_image (GdkDrawable *drawable,
gint width,
gint height);
-static GdkImage* gdk_window_get_image (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height);
-
+static void gdk_window_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither);
+
+static GdkImage* gdk_window_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height);
static void gdk_window_real_get_size (GdkDrawable *drawable,
gint *width,
@@ -223,12 +238,13 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
drawable_class->draw_lines = gdk_window_draw_lines;
drawable_class->draw_glyphs = gdk_window_draw_glyphs;
drawable_class->draw_image = gdk_window_draw_image;
+ drawable_class->_draw_pixbuf = gdk_window_draw_pixbuf;
drawable_class->get_depth = gdk_window_real_get_depth;
drawable_class->get_size = gdk_window_real_get_size;
drawable_class->set_colormap = gdk_window_real_set_colormap;
drawable_class->get_colormap = gdk_window_real_get_colormap;
drawable_class->get_visual = gdk_window_real_get_visual;
- drawable_class->get_image = gdk_window_get_image;
+ drawable_class->_copy_to_image = gdk_window_copy_to_image;
drawable_class->get_clip_region = gdk_window_get_clip_region;
drawable_class->get_visible_region = gdk_window_get_visible_region;
drawable_class->get_composite_drawable = gdk_window_get_composite_drawable;
@@ -1862,6 +1878,65 @@ gdk_window_draw_image (GdkDrawable *drawable,
RESTORE_GC (gc);
}
+static void
+gdk_window_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither)
+{
+ GdkWindowObject *private = (GdkWindowObject *)drawable;
+
+ if (GDK_WINDOW_DESTROYED (drawable))
+ return;
+
+ if (gc)
+ {
+ OFFSET_GC (gc);
+
+ if (private->paint_stack)
+ {
+ GdkWindowPaint *paint = private->paint_stack->data;
+ _gdk_draw_pixbuf (paint->pixmap, gc, pixbuf, src_x, src_y,
+ dest_x - x_offset, dest_y - y_offset,
+ width, height,
+ dither, x_dither - x_offset, y_dither - y_offset);
+ }
+ else
+ _gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y,
+ dest_x - x_offset, dest_y - y_offset,
+ width, height,
+ dither, x_dither, y_dither);
+
+ RESTORE_GC (gc);
+ }
+ else
+ {
+ gint x_offset, y_offset;
+ gdk_window_get_offsets (drawable, &x_offset, &y_offset);
+
+ if (private->paint_stack)
+ {
+ GdkWindowPaint *paint = private->paint_stack->data;
+ _gdk_draw_pixbuf (paint->pixmap, gc, pixbuf, src_x, src_y,
+ dest_x - x_offset, dest_y - y_offset,
+ width, height,
+ dither, x_dither - x_offset, y_dither - y_offset);
+ }
+ else
+ _gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y,
+ dest_x - x_offset, dest_y - y_offset,
+ width, height,
+ dither, x_dither, y_dither);
+ }
+}
static void
gdk_window_real_get_size (GdkDrawable *drawable,
@@ -1927,11 +2002,14 @@ gdk_window_real_get_colormap (GdkDrawable *drawable)
}
static GdkImage*
-gdk_window_get_image (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height)
+gdk_window_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height)
{
gint x_offset, y_offset;
@@ -1946,10 +2024,12 @@ gdk_window_get_image (GdkDrawable *drawable,
_gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
- return gdk_drawable_get_image (((GdkWindowObject*)drawable)->impl,
- x - x_offset,
- y - y_offset,
- width, height);
+ return _gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl,
+ image,
+ src_x - x_offset,
+ src_y - y_offset,
+ dest_x, dest_y,
+ width, height);
}
/* Code for dirty-region queueing
diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c
index 0ca8d1220..96f6b05f8 100644
--- a/gdk/x11/gdkdrawable-x11.c
+++ b/gdk/x11/gdkdrawable-x11.c
@@ -35,6 +35,7 @@
#endif
#include <stdlib.h>
+#include <string.h> /* for memcpy() */
#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
#define USE_SHM
@@ -119,6 +120,20 @@ static void gdk_x11_draw_image (GdkDrawable *drawable,
gint ydest,
gint width,
gint height);
+#ifdef HAVE_XFT
+static void gdk_x11_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither);
+#endif /* HAVE_XFT */
static void gdk_x11_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap);
@@ -185,6 +200,9 @@ gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass)
drawable_class->draw_lines = gdk_x11_draw_lines;
drawable_class->draw_glyphs = gdk_x11_draw_glyphs;
drawable_class->draw_image = gdk_x11_draw_image;
+#ifdef HAVE_XFT
+ drawable_class->_draw_pixbuf = gdk_x11_draw_pixbuf;
+#endif /* HAVE_XFT */
drawable_class->set_colormap = gdk_x11_set_colormap;
drawable_class->get_colormap = gdk_x11_get_colormap;
@@ -192,7 +210,7 @@ gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass)
drawable_class->get_depth = gdk_x11_get_depth;
drawable_class->get_visual = gdk_x11_get_visual;
- drawable_class->get_image = _gdk_x11_get_image;
+ drawable_class->_copy_to_image = _gdk_x11_copy_to_image;
}
static void
@@ -204,6 +222,17 @@ gdk_drawable_impl_x11_finalize (GObject *object)
}
#ifdef HAVE_XFT
+gboolean
+_gdk_x11_have_render (void)
+{
+ /* This check is cheap, but if we have to do version checks, we will
+ * need to cache the result since version checks are round-trip
+ */
+ int event_base, error_base;
+
+ return XRenderQueryExtension (gdk_display, &event_base, &error_base);
+}
+
static Picture
gdk_x11_drawable_get_picture (GdkDrawable *drawable)
{
@@ -225,7 +254,8 @@ gdk_x11_drawable_get_picture (GdkDrawable *drawable)
}
format = XRenderFindVisualFormat (impl->xdisplay, GDK_VISUAL_XVISUAL (visual));
- impl->picture = XRenderCreatePicture (impl->xdisplay, impl->xid, format, 0, NULL);
+ if (format)
+ impl->picture = XRenderCreatePicture (impl->xdisplay, impl->xid, format, 0, NULL);
}
return impl->picture;
@@ -752,3 +782,536 @@ gdk_x11_drawable_get_xid (GdkDrawable *drawable)
return ((GdkDrawableImplX11 *)impl)->xid;
}
+
+/* Code for accelerated alpha compositing using the RENDER extension.
+ * It's a bit long because there are lots of possibilities for
+ * what's the fastest depending on the available picture formats,
+ * whether we can used shared pixmaps, etc.
+ */
+#ifdef HAVE_XFT
+typedef enum {
+ FORMAT_NONE,
+ FORMAT_EXACT_MASK,
+ FORMAT_ARGB_MASK,
+ FORMAT_ARGB
+} FormatType;
+
+static FormatType
+select_format (Display *xdisplay,
+ XRenderPictFormat **format,
+ XRenderPictFormat **mask)
+{
+ XRenderPictFormat pf;
+
+
+/* Look for a 32-bit xRGB and Axxx formats that exactly match the
+ * in memory data format. We can use them as pixmap and mask
+ * to deal with non-premultiplied data.
+ */
+
+ pf.type = PictTypeDirect;
+ pf.depth = 32;
+ pf.direct.redMask = 0xff;
+ pf.direct.greenMask = 0xff;
+ pf.direct.blueMask = 0xff;
+
+ pf.direct.alphaMask = 0;
+ if (ImageByteOrder (xdisplay) == LSBFirst)
+ {
+ /* ABGR */
+ pf.direct.red = 0;
+ pf.direct.green = 8;
+ pf.direct.blue = 16;
+ }
+ else
+ {
+ /* RGBA */
+ pf.direct.red = 24;
+ pf.direct.green = 16;
+ pf.direct.blue = 8;
+ }
+
+ *format = XRenderFindFormat (xdisplay,
+ (PictFormatType | PictFormatDepth |
+ PictFormatRedMask | PictFormatRed |
+ PictFormatGreenMask | PictFormatGreen |
+ PictFormatBlueMask | PictFormatBlue |
+ PictFormatAlphaMask),
+ &pf,
+ 0);
+
+ pf.direct.alphaMask = 0xff;
+ if (ImageByteOrder (xdisplay) == LSBFirst)
+ {
+ /* ABGR */
+ pf.direct.alpha = 24;
+ }
+ else
+ {
+ pf.direct.alpha = 0;
+ }
+
+ *mask = XRenderFindFormat (xdisplay,
+ (PictFormatType | PictFormatDepth |
+ PictFormatAlphaMask | PictFormatAlpha),
+ &pf,
+ 0);
+
+ if (*format && *mask)
+ return FORMAT_EXACT_MASK;
+
+ /* OK, that failed, now look for xRGB and Axxx formats in
+ * RENDER's preferred order
+ */
+ pf.direct.alphaMask = 0;
+ /* ARGB */
+ pf.direct.red = 16;
+ pf.direct.green = 8;
+ pf.direct.blue = 0;
+
+ *format = XRenderFindFormat (xdisplay,
+ (PictFormatType | PictFormatDepth |
+ PictFormatRedMask | PictFormatRed |
+ PictFormatGreenMask | PictFormatGreen |
+ PictFormatBlueMask | PictFormatBlue |
+ PictFormatAlphaMask),
+ &pf,
+ 0);
+
+ pf.direct.alphaMask = 0xff;
+ pf.direct.alpha = 24;
+
+ *mask = XRenderFindFormat (xdisplay,
+ (PictFormatType | PictFormatDepth |
+ PictFormatAlphaMask | PictFormatAlpha),
+ &pf,
+ 0);
+
+ if (*format && *mask)
+ return FORMAT_ARGB_MASK;
+
+ /* Finally, if neither of the above worked, fall back to
+ * looking for combined ARGB -- we'll premultiply ourselves.
+ */
+
+ pf.type = PictTypeDirect;
+ pf.depth = 32;
+ pf.direct.red = 16;
+ pf.direct.green = 8;
+ pf.direct.blue = 0;
+ pf.direct.alphaMask = 0xff;
+ pf.direct.alpha = 24;
+
+ *format = XRenderFindFormat (xdisplay,
+ (PictFormatType | PictFormatDepth |
+ PictFormatRedMask | PictFormatRed |
+ PictFormatGreenMask | PictFormatGreen |
+ PictFormatBlueMask | PictFormatBlue |
+ PictFormatAlphaMask | PictFormatAlpha),
+ &pf,
+ 0);
+ *mask = NULL;
+
+ if (*format)
+ return FORMAT_ARGB;
+
+ return FORMAT_NONE;
+}
+
+#if 0
+static void
+list_formats (XRenderPictFormat *pf)
+{
+ gint i;
+
+ for (i=0 ;; i++)
+ {
+ XRenderPictFormat *pf = XRenderFindFormat (impl->xdisplay, 0, NULL, i);
+ if (pf)
+ {
+ g_print ("%2d R-%#06x/%#06x G-%#06x/%#06x B-%#06x/%#06x A-%#06x/%#06x\n",
+ pf->depth,
+ pf->direct.red,
+ pf->direct.redMask,
+ pf->direct.green,
+ pf->direct.greenMask,
+ pf->direct.blue,
+ pf->direct.blueMask,
+ pf->direct.alpha,
+ pf->direct.alphaMask);
+ }
+ else
+ break;
+ }
+}
+#endif
+
+static void
+convert_to_format (guchar *src_buf,
+ gint src_rowstride,
+ guchar *dest_buf,
+ gint dest_rowstride,
+ FormatType dest_format,
+ GdkByteOrder dest_byteorder,
+ gint width,
+ gint height)
+{
+ gint i;
+
+ if (dest_format == FORMAT_EXACT_MASK &&
+ src_rowstride == dest_rowstride)
+ {
+ memcpy (dest_buf, src_buf, height * src_rowstride);
+ return;
+ }
+
+ for (i=0; i < height; i++)
+ {
+ switch (dest_format)
+ {
+ case FORMAT_EXACT_MASK:
+ {
+ memcpy (dest_buf + i * dest_rowstride,
+ src_buf + i * src_rowstride,
+ width * 4);
+ break;
+ }
+ case FORMAT_ARGB_MASK:
+ {
+ guint *p = (guint *)(src_buf + i * src_rowstride);
+ guint *q = (guint *)(dest_buf + i * dest_rowstride);
+ guint *end = p + width;
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ if (dest_byteorder == GDK_LSB_FIRST)
+ {
+ /* ABGR => ARGB */
+
+ while (p < end)
+ {
+ *q = ( (*p & 0xff00ff00) |
+ ((*p & 0x000000ff) << 16) |
+ ((*p & 0x00ff0000) >> 16));
+ q++;
+ p++;
+ }
+ }
+ else
+ {
+ /* ABGR => BGRA */
+
+ while (p < end)
+ {
+ *q = (((*p & 0xff000000) >> 24) |
+ ((*p & 0x00ffffff) << 8));
+ q++;
+ p++;
+ }
+ }
+#else /* G_BYTE_ORDER == G_BIG_ENDIAN */
+ if (dest_byteorder == GDK_LSB_FIRST)
+ {
+ /* RGBA => BGRA */
+
+ while (p < end)
+ {
+ *q = ( (*p & 0x00ff00ff) |
+ ((*p & 0x0000ff00) << 16) |
+ ((*p & 0xff000000) >> 16));
+ q++;
+ p++;
+ }
+ }
+ else
+ {
+ /* RGBA => ARGB */
+
+ while (p < end)
+ {
+ *q = (((*p & 0xff000000) >> 24) |
+ ((*p & 0x00ffffff) << 8));
+ q++;
+ p++;
+ }
+ }
+#endif /* G_BYTE_ORDER*/
+ break;
+ }
+ case FORMAT_ARGB:
+ {
+ guchar *p = (src_buf + i * src_rowstride);
+ guchar *q = (dest_buf + i * dest_rowstride);
+ guchar *end = p + 4 * width;
+ guchar a;
+ guint t;
+
+#define MULT(d,c,a) G_STMT_START { t = c * a; d = ((t >> 8) + t) >> 8; } G_STMT_END
+
+ if (dest_byteorder == GDK_LSB_FIRST)
+ {
+ while (p < end)
+ {
+ a = p[3];
+ MULT(q[0], p[2], a);
+ MULT(q[1], p[1], a);
+ MULT(q[2], p[0], a);
+ q[3] = a;
+ p += 4;
+ q += 4;
+ }
+ }
+ else
+ {
+ while (p < end)
+ {
+ a = p[3];
+ q[0] = a;
+ MULT(q[1], p[0], a);
+ MULT(q[2], p[1], a);
+ MULT(q[3], p[2], a);
+ p += 4;
+ q += 4;
+ }
+ }
+#undef MULT
+ break;
+ }
+ case FORMAT_NONE:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+}
+
+static void
+draw_with_images (GdkDrawable *drawable,
+ GdkGC *gc,
+ FormatType format_type,
+ XRenderPictFormat *format,
+ XRenderPictFormat *mask_format,
+ guchar *src_rgb,
+ gint src_rowstride,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height)
+{
+ Display *xdisplay = GDK_DRAWABLE_IMPL_X11 (drawable)->xdisplay;
+ GdkImage *image;
+ GdkPixmap *pix;
+ GdkGC *pix_gc;
+ Picture pict;
+ Picture dest_pict;
+ Picture mask = None;
+ gint x0, y0;
+
+ pix = gdk_pixmap_new (NULL, width, height, 32);
+ pict = XRenderCreatePicture (xdisplay,
+ GDK_PIXMAP_XID (pix),
+ format, 0, NULL);
+ if (mask_format)
+ mask = XRenderCreatePicture (xdisplay,
+ GDK_PIXMAP_XID (pix),
+ mask_format, 0, NULL);
+
+ dest_pict = gdk_x11_drawable_get_picture (drawable);
+
+ pix_gc = gdk_gc_new (pix);
+
+ for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
+ {
+ gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
+ for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
+ {
+ gint xs0, ys0;
+
+ gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
+
+ image = _gdk_image_get_scratch (width1, height1, 32, &xs0, &ys0);
+
+ convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride,
+ image->mem + ys0 * image->bpl + 4 * xs0, image->bpl,
+ format_type, image->byte_order,
+ width1, height1);
+
+ gdk_draw_image (pix, pix_gc,
+ image, xs0, ys0, x0, y0, width1, height1);
+ }
+ }
+
+ XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict,
+ 0, 0, 0, 0, dest_x, dest_y, width, height);
+
+ XRenderFreePicture (xdisplay, pict);
+ if (mask)
+ XRenderFreePicture (xdisplay, mask);
+
+ g_object_unref (pix);
+ g_object_unref (pix_gc);
+}
+
+typedef struct _ShmPixmapInfo ShmPixmapInfo;
+
+struct _ShmPixmapInfo
+{
+ GdkImage *image;
+ Pixmap pix;
+ Picture pict;
+ Picture mask;
+};
+
+/* Returns FALSE if we can't get a shm pixmap */
+static gboolean
+get_shm_pixmap_for_image (Display *xdisplay,
+ GdkImage *image,
+ XRenderPictFormat *format,
+ XRenderPictFormat *mask_format,
+ Pixmap *pix,
+ Picture *pict,
+ Picture *mask)
+{
+ ShmPixmapInfo *info;
+
+ if (image->type != GDK_IMAGE_SHARED)
+ return FALSE;
+
+ info = g_object_get_data (G_OBJECT (image), "gdk-x11-shm-pixmap");
+ if (!info)
+ {
+ *pix = _gdk_x11_image_get_shm_pixmap (image);
+
+ if (!*pix)
+ return FALSE;
+
+ info = g_new (ShmPixmapInfo, 1);
+ info->pix = *pix;
+
+ info->pict = XRenderCreatePicture (xdisplay, info->pix,
+ format, 0, NULL);
+ if (mask_format)
+ info->mask = XRenderCreatePicture (xdisplay, info->pix,
+ mask_format, 0, NULL);
+ else
+ info->mask = None;
+
+ g_object_set_data (G_OBJECT (image), "gdk-x11-shm-pixmap", info);
+ }
+
+ *pix = info->pix;
+ *pict = info->pict;
+ *mask = info->mask;
+
+ return TRUE;
+}
+
+#ifdef USE_SHM
+/* Returns FALSE if drawing with ShmPixmaps is not possible */
+static gboolean
+draw_with_pixmaps (GdkDrawable *drawable,
+ GdkGC *gc,
+ FormatType format_type,
+ XRenderPictFormat *format,
+ XRenderPictFormat *mask_format,
+ guchar *src_rgb,
+ gint src_rowstride,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height)
+{
+ Display *xdisplay = GDK_DRAWABLE_IMPL_X11 (drawable)->xdisplay;
+ GdkImage *image;
+ Pixmap pix;
+ Picture pict;
+ Picture dest_pict;
+ Picture mask = None;
+ gint x0, y0;
+
+ dest_pict = gdk_x11_drawable_get_picture (drawable);
+
+ for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
+ {
+ gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
+ for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
+ {
+ gint xs0, ys0;
+
+ gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
+
+ image = _gdk_image_get_scratch (width1, height1, 32, &xs0, &ys0);
+ if (!get_shm_pixmap_for_image (xdisplay, image, format, mask_format, &pix, &pict, &mask))
+ return FALSE;
+
+ convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride,
+ image->mem + ys0 * image->bpl + 4 * xs0, image->bpl,
+ format_type, image->byte_order,
+ width1, height1);
+
+ XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict,
+ xs0, ys0, xs0, ys0, x0 + dest_x, y0 + dest_y,
+ width1, height1);
+ }
+ }
+
+ return TRUE;
+}
+#endif
+
+static void
+gdk_x11_draw_pixbuf (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixbuf *pixbuf,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height,
+ GdkRgbDither dither,
+ gint x_dither,
+ gint y_dither)
+{
+ Display *xdisplay = GDK_DRAWABLE_IMPL_X11 (drawable)->xdisplay;
+ FormatType format_type;
+ XRenderPictFormat *format, *mask_format;
+ gint rowstride;
+#ifdef USE_SHM
+ gboolean use_pixmaps = TRUE;
+#endif /* USE_SHM */
+
+ format_type = select_format (xdisplay, &format, &mask_format);
+
+ if (format_type == FORMAT_NONE ||
+ !gdk_pixbuf_get_has_alpha (pixbuf) ||
+ (dither == GDK_RGB_DITHER_MAX && gdk_drawable_get_depth (drawable) != 24))
+ {
+ GdkDrawable *wrapper = GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper;
+ GDK_DRAWABLE_CLASS (parent_class)->_draw_pixbuf (wrapper, gc, pixbuf,
+ src_x, src_y, dest_x, dest_y,
+ width, height,
+ dither, x_dither, y_dither);
+ return;
+ }
+
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+#ifdef USE_SHM
+ if (use_pixmaps)
+ {
+ if (!draw_with_pixmaps (drawable, gc,
+ format_type, format, mask_format,
+ gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4,
+ rowstride,
+ dest_x, dest_y, width, height))
+ use_pixmaps = FALSE;
+ }
+
+ if (!use_pixmaps)
+#endif /* USE_SHM */
+ draw_with_images (drawable, gc,
+ format_type, format, mask_format,
+ gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4,
+ rowstride,
+ dest_x, dest_y, width, height);
+}
+#endif /* HAVE_XFT */
diff --git a/gdk/x11/gdkgc-x11.c b/gdk/x11/gdkgc-x11.c
index 7412eb726..b703b7e3b 100644
--- a/gdk/x11/gdkgc-x11.c
+++ b/gdk/x11/gdkgc-x11.c
@@ -810,9 +810,13 @@ _gdk_x11_gc_get_fg_picture (GdkGC *gc)
{
XRenderPictureAttributes pa;
XRenderPictFormat *pix_format = foreground_format (gc);
+ Pixmap pix;
- Pixmap pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window,
- 1, 1, pix_format->depth);
+ if (!pix_format)
+ return None;
+
+ pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window,
+ 1, 1, pix_format->depth);
pa.repeat = True;
x11_gc->fg_picture = XRenderCreatePicture (x11_gc->xdisplay,
pix,
diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c
index 21302d7e6..4f03ff8de 100644
--- a/gdk/x11/gdkimage-x11.c
+++ b/gdk/x11/gdkimage-x11.c
@@ -59,10 +59,12 @@ struct _GdkImagePrivateX11
XImage *ximage;
Display *xdisplay;
gpointer x_shm_info;
+ Pixmap shm_pixmap;
};
static GList *image_list = NULL;
static gpointer parent_class = NULL;
+static gboolean have_shm_pixmaps;
static void gdk_x11_image_destroy (GdkImage *image);
static void gdk_image_init (GdkImage *image);
@@ -198,33 +200,42 @@ _gdk_windowing_image_init (void)
{
if (_gdk_use_xshm)
{
- if (!gdk_image_check_xshm (gdk_display))
- {
- _gdk_use_xshm = False;
- }
+ gint res = gdk_image_check_xshm (gdk_display);
+
+ if (!res)
+ _gdk_use_xshm = FALSE;
+ else
+ have_shm_pixmaps = (res == 2);
}
}
GdkImage*
-gdk_image_new (GdkImageType type,
- GdkVisual *visual,
- gint width,
- gint height)
+_gdk_image_new_for_depth (GdkImageType type,
+ GdkVisual *visual,
+ gint width,
+ gint height,
+ gint depth)
{
GdkImage *image;
GdkImagePrivateX11 *private;
#ifdef USE_SHM
XShmSegmentInfo *x_shm_info;
#endif /* USE_SHM */
- Visual *xvisual;
+ Visual *xvisual = NULL;
+ g_return_val_if_fail (!visual || GDK_IS_VISUAL (visual), NULL);
+ g_return_val_if_fail (visual || depth != -1, NULL);
+
+ if (visual)
+ depth = visual->depth;
+
switch (type)
{
case GDK_IMAGE_FASTEST:
- image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height);
+ image = _gdk_image_new_for_depth (GDK_IMAGE_SHARED, visual, width, height, depth);
if (!image)
- image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height);
+ image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height, depth);
break;
default:
@@ -238,9 +249,10 @@ gdk_image_new (GdkImageType type,
image->visual = visual;
image->width = width;
image->height = height;
- image->depth = visual->depth;
+ image->depth = depth;
- xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+ if (visual)
+ xvisual = ((GdkVisualPrivate*) visual)->xvisual;
switch (type)
{
@@ -253,7 +265,7 @@ gdk_image_new (GdkImageType type,
x_shm_info->shmid = -1;
x_shm_info->shmaddr = (char*) -1;
- private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth,
+ private->ximage = XShmCreateImage (private->xdisplay, xvisual, depth,
ZPixmap, NULL, x_shm_info, width, height);
if (private->ximage == NULL)
{
@@ -326,7 +338,7 @@ gdk_image_new (GdkImageType type,
goto error;
break;
case GDK_IMAGE_NORMAL:
- private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth,
+ private->ximage = XCreateImage (private->xdisplay, xvisual, depth,
ZPixmap, 0, 0, width, height, 32, 0);
/* Use malloc, not g_malloc here, because X will call free()
@@ -344,7 +356,7 @@ gdk_image_new (GdkImageType type,
if (image)
{
- image->byte_order = private->ximage->byte_order;
+ image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
image->mem = private->ximage->data;
image->bpl = private->ximage->bytes_per_line;
image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
@@ -379,39 +391,144 @@ gdk_image_new (GdkImageType type,
return NULL;
}
+Pixmap
+_gdk_x11_image_get_shm_pixmap (GdkImage *image)
+{
+ GdkImagePrivateX11 *private = PRIVATE_DATA (image);
+
+#ifdef USE_SHM
+ /* Future: do we need one of these per-screen per-image? ShmPixmaps
+ * are the same for every screen, but can they be shared?
+ */
+ if (!private->shm_pixmap && image->type == GDK_IMAGE_SHARED && have_shm_pixmaps)
+ private->shm_pixmap = XShmCreatePixmap (private->xdisplay, _gdk_root_window,
+ image->mem, private->x_shm_info,
+ image->width, image->height, image->depth);
+
+ return private->shm_pixmap;
+#else
+ return None;
+#endif
+}
+
GdkImage*
-_gdk_x11_get_image (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height)
+gdk_image_new (GdkImageType type,
+ GdkVisual *visual,
+ gint width,
+ gint height)
+{
+ return _gdk_image_new_for_depth (type, visual, width, height, -1);
+}
+
+GdkImage*
+get_full_image (GdkDrawable *drawable,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
{
GdkImage *image;
GdkImagePrivateX11 *private;
GdkDrawableImplX11 *impl;
+ XImage *ximage;
+
+ impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+
+ ximage = XGetImage (impl->xdisplay,
+ impl->xid,
+ src_x, src_y, width, height,
+ AllPlanes, ZPixmap);
+
+ if (!ximage)
+ return NULL;
+
+ image = g_object_new (gdk_image_get_type (), NULL);
+
+ private = PRIVATE_DATA (image);
+
+ private->xdisplay = gdk_display;
+ private->ximage = ximage;
+
+ image->type = GDK_IMAGE_NORMAL;
+ image->visual = gdk_drawable_get_visual (drawable); /* could be NULL */
+ image->width = width;
+ image->height = height;
+ image->depth = gdk_drawable_get_depth (drawable);
+
+ image->mem = private->ximage->data;
+ image->bpl = private->ximage->bytes_per_line;
+ image->bits_per_pixel = private->ximage->bits_per_pixel;
+ image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
+ image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
+
+ return image;
+}
+
+GdkImage*
+_gdk_x11_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height)
+{
+ GdkImagePrivateX11 *private;
+ GdkDrawableImplX11 *impl;
GdkVisual *visual;
gboolean have_grab;
GdkRectangle req;
GdkRectangle window_rect;
- XImage *ximage;
+ Pixmap shm_pixmap = None;
+ gboolean success = TRUE;
g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
+ g_return_val_if_fail (image != NULL || (dest_x == 0 && dest_y == 0), NULL);
visual = gdk_drawable_get_visual (drawable);
-
- g_assert (visual || !GDK_IS_WINDOW_IMPL_X11 (drawable));
-
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
have_grab = FALSE;
+#define UNGRAB() G_STMT_START { \
+ if (have_grab) { \
+ gdk_x11_ungrab_server (); \
+ XFlush (impl->xdisplay); \
+ have_grab = FALSE; } \
+ } G_STMT_END
+
+ if (!image && !GDK_IS_WINDOW_IMPL_X11 (drawable))
+ return get_full_image (drawable, src_x, src_y, width, height);
+
+ if (image && image->type == GDK_IMAGE_SHARED)
+ {
+ shm_pixmap = _gdk_x11_image_get_shm_pixmap (image);
+ if (shm_pixmap)
+ {
+ /* Again easy, we can just XCopyArea, and don't have to worry about clipping
+ */
+ GC xgc = XCreateGC (impl->xdisplay, impl->xid, 0, NULL);
+
+ XCopyArea (impl->xdisplay, impl->xid, shm_pixmap, xgc,
+ src_x, src_y, width, height, dest_x, dest_y);
+ XSync (impl->xdisplay, FALSE);
+
+ XFreeGC (impl->xdisplay, xgc);
+
+ return image;
+ }
+ }
+
+ /* Now the general case - we may have to worry about clipping to the screen
+ * bounds, in which case we'll have to grab the server and only get a piece
+ * of the window.
+ */
if (GDK_IS_WINDOW_IMPL_X11 (drawable))
{
GdkRectangle screen_rect;
Window child;
- g_assert (visual);
-
have_grab = TRUE;
gdk_x11_grab_server ();
@@ -443,13 +560,7 @@ _gdk_x11_get_image (GdkDrawable *drawable,
if (gdk_error_trap_pop () ||
!gdk_rectangle_intersect (&window_rect, &screen_rect,
&window_rect))
- {
- if (have_grab)
- gdk_x11_ungrab_server ();
- return image = gdk_image_new (GDK_IMAGE_FASTEST,
- visual,
- width, height);
- }
+ goto out;
}
else
{
@@ -460,8 +571,8 @@ _gdk_x11_get_image (GdkDrawable *drawable,
&window_rect.height);
}
- req.x = x;
- req.y = y;
+ req.x = src_x;
+ req.y = src_y;
req.width = width;
req.height = height;
@@ -470,97 +581,66 @@ _gdk_x11_get_image (GdkDrawable *drawable,
* For pixmaps this is all of the pixmap, for windows it is just
* the onscreen part.
*/
- if (!gdk_rectangle_intersect (&req, &window_rect, &req) && visual)
- {
- if (have_grab)
- gdk_x11_ungrab_server ();
- return image = gdk_image_new (GDK_IMAGE_FASTEST,
- visual,
- width, height);
- }
-
- if (req.x != x || req.y != y)
- {
- g_assert (GDK_IS_WINDOW (drawable));
- g_assert (visual);
-
- image = gdk_image_new (GDK_IMAGE_FASTEST,
- visual,
- width, height);
- if (image == NULL)
- {
- if (have_grab)
- gdk_x11_ungrab_server ();
- return NULL;
- }
-
- private = PRIVATE_DATA (image);
+ if (!gdk_rectangle_intersect (&req, &window_rect, &req))
+ goto out;
- gdk_error_trap_push ();
-
- ximage = XGetSubImage (impl->xdisplay,
- impl->xid,
- req.x, req.y, req.width, req.height,
- AllPlanes, ZPixmap,
- private->ximage,
- req.x - x, req.y - y);
-
- if (have_grab)
- {
- gdk_x11_ungrab_server ();
- have_grab = FALSE;
- }
-
- if (gdk_error_trap_pop () || ximage == NULL)
- {
- g_object_unref (G_OBJECT (image));
- return NULL;
- }
+ private = PRIVATE_DATA (image);
- g_assert (ximage == private->ximage);
+ gdk_error_trap_push ();
+
+ if (!image &&
+ req.x == src_x && req.y == src_y && req.width == width && req.height == height)
+ {
+ image = get_full_image (drawable, src_x, src_y, width, height);
+ if (!image)
+ success = FALSE;
}
else
{
- /* Here we ignore the req.width, req.height -
- * XGetImage() will do the right thing without
- * them.
- */
- ximage = XGetImage (impl->xdisplay,
- impl->xid,
- x, y, width, height,
- AllPlanes, ZPixmap);
-
- if (have_grab)
- {
- gdk_x11_ungrab_server ();
- have_grab = FALSE;
- }
-
- if (!ximage)
- return NULL;
-
- image = g_object_new (gdk_image_get_type (), NULL);
-
- private = PRIVATE_DATA (image);
-
- private->xdisplay = gdk_display;
- private->ximage = ximage;
-
- image->type = GDK_IMAGE_NORMAL;
- image->visual = visual; /* May be NULL */
- image->width = width;
- image->height = height;
- image->depth = gdk_drawable_get_depth (drawable);
+ gboolean created_image = FALSE;
+
+ if (!image)
+ {
+ image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height,
+ gdk_drawable_get_depth (drawable));
+ created_image = TRUE;
+ }
- image->mem = private->ximage->data;
- image->bpl = private->ximage->bytes_per_line;
- image->bits_per_pixel = private->ximage->bits_per_pixel;
- image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
- image->byte_order = private->ximage->byte_order;
+ /* In the ShmImage but no ShmPixmap case, we could use XShmGetImage when
+ * we are getting the entire image.
+ */
+ if (XGetSubImage (impl->xdisplay,
+ impl->xid,
+ req.x, req.y, req.width, req.height,
+ AllPlanes, ZPixmap,
+ private->ximage,
+ dest_x + req.x - src_x, dest_y + req.y - src_y) == None)
+ {
+ if (created_image)
+ g_object_unref (image);
+ image = NULL;
+ success = FALSE;
+ }
}
- g_assert (!have_grab);
+ out:
+
+ if (have_grab)
+ {
+ gdk_x11_ungrab_server ();
+ XFlush (impl->xdisplay);
+ have_grab = FALSE;
+ }
+ gdk_error_trap_pop ();
+
+ if (success && !image)
+ {
+ /* We "succeeded", but could get no content for the image so return junk */
+ image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height,
+ gdk_drawable_get_depth (drawable));
+ }
+
return image;
}
@@ -625,7 +705,11 @@ gdk_x11_image_destroy (GdkImage *image)
case GDK_IMAGE_SHARED:
#ifdef USE_SHM
gdk_flush();
-
+
+ if (private->shm_pixmap)
+ XFreePixmap (private->xdisplay, private->shm_pixmap);
+
+ image_list = g_list_remove (image_list, image);
XShmDetach (private->xdisplay, private->x_shm_info);
XDestroyImage (private->ximage);
@@ -634,8 +718,7 @@ gdk_x11_image_destroy (GdkImage *image)
g_free (private->x_shm_info);
private->x_shm_info = NULL;
-
- image_list = g_list_remove (image_list, image);
+
#else /* USE_SHM */
g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
#endif /* USE_SHM */
@@ -673,3 +756,23 @@ gdk_x11_image_get_ximage (GdkImage *image)
return private->ximage;
}
+
+gint
+_gdk_windowing_get_bits_for_depth (gint depth)
+{
+ XPixmapFormatValues *formats;
+ gint count, i;
+
+ formats = XListPixmapFormats (gdk_display, &count);
+
+ for (i = 0; i < count; i++)
+ if (formats[i].depth == depth)
+ {
+ gint result = formats[i].bits_per_pixel;
+ XFree (formats);
+ return result;
+ }
+
+ g_assert_not_reached ();
+ return -1;
+}
diff --git a/gdk/x11/gdkpango-x11.c b/gdk/x11/gdkpango-x11.c
index 411bf01b2..a823cf96a 100644
--- a/gdk/x11/gdkpango-x11.c
+++ b/gdk/x11/gdkpango-x11.c
@@ -49,7 +49,7 @@ gdk_pango_context_get (void)
{
const char *val = g_getenv ("GDK_USE_XFT");
- use_xft = val && (atoi (val) != 0);
+ use_xft = val && (atoi (val) != 0) && _gdk_x11_have_render ();
}
if (use_xft)
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 6552ff538..a495c5187 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -100,7 +100,8 @@ gint gdk_send_xevent (Window window,
GType _gdk_gc_x11_get_type (void);
#ifdef HAVE_XFT
-Picture _gdk_x11_gc_get_fg_picture (GdkGC *gc);
+gboolean _gdk_x11_have_render (void);
+Picture _gdk_x11_gc_get_fg_picture (GdkGC *gc);
#endif /* HAVE_XFT */
GdkGC *_gdk_x11_gc_new (GdkDrawable *drawable,
@@ -112,11 +113,15 @@ GdkVisual * gdk_visual_lookup (Visual *xvisual);
void gdk_window_add_colormap_windows (GdkWindow *window);
-GdkImage* _gdk_x11_get_image (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height);
+GdkImage *_gdk_x11_copy_to_image (GdkDrawable *drawable,
+ GdkImage *image,
+ gint src_x,
+ gint src_y,
+ gint dest_x,
+ gint dest_y,
+ gint width,
+ gint height);
+Pixmap _gdk_x11_image_get_shm_pixmap (GdkImage *image);
/* Please see gdkwindow.c for comments on how to use */
Window gdk_window_xid_at (Window base,
diff --git a/tests/testrgb.c b/tests/testrgb.c
index 12f088f60..9a61f92f8 100644
--- a/tests/testrgb.c
+++ b/tests/testrgb.c
@@ -48,7 +48,7 @@ quit_func (GtkWidget *widget, gpointer dummy)
#define WIDTH 640
#define HEIGHT 400
-#define NUM_ITERS 100
+#define NUM_ITERS 50
static void
testrgb_rgb_test (GtkWidget *drawing_area)
@@ -62,11 +62,13 @@ testrgb_rgb_test (GtkWidget *drawing_area)
gboolean dither;
int dith_max;
GTimer *timer;
-
- buf = g_malloc (WIDTH * HEIGHT * 6);
+ GdkPixbuf *pixbuf;
+ gboolean to_pixmap;
+
+ buf = g_malloc (WIDTH * HEIGHT * 8);
val = 0;
- for (j = 0; j < WIDTH * HEIGHT * 6; j++)
+ for (j = 0; j < WIDTH * HEIGHT * 8; j++)
{
val = (val + ((val + (rand () & 0xff)) >> 1)) >> 1;
buf[j] = val;
@@ -103,6 +105,7 @@ testrgb_rgb_test (GtkWidget *drawing_area)
GDK_RGB_DITHER_NONE,
buf + offset, WIDTH * 3);
}
+ gdk_flush ();
total_time = g_timer_elapsed (timer, NULL) - start_time;
g_print ("Color test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n",
dither ? " (dithered)" : "",
@@ -124,6 +127,7 @@ testrgb_rgb_test (GtkWidget *drawing_area)
GDK_RGB_DITHER_NONE,
buf + offset, WIDTH);
}
+ gdk_flush ();
total_time = g_timer_elapsed (timer, NULL) - start_time;
g_print ("Grayscale test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n",
dither ? " (dithered)" : "",
@@ -132,6 +136,42 @@ testrgb_rgb_test (GtkWidget *drawing_area)
NUM_ITERS * (WIDTH * HEIGHT * 1e-6) / total_time);
}
+ for (to_pixmap = FALSE; to_pixmap <= TRUE; to_pixmap++)
+ {
+ if (to_pixmap)
+ {
+ GdkRectangle rect = { 0, 0, WIDTH, HEIGHT };
+ gdk_window_begin_paint_rect (drawing_area->window, &rect);
+ }
+
+ start_time = g_timer_elapsed (timer, NULL);
+ for (i = 0; i < NUM_ITERS; i++)
+ {
+ offset = (rand () % (WIDTH * HEIGHT * 4)) & -4;
+ pixbuf = gdk_pixbuf_new_from_data (buf + offset, GDK_COLORSPACE_RGB, TRUE,
+ 8, WIDTH, HEIGHT, WIDTH * 4,
+ NULL, NULL);
+ gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawing_area->window,
+ 0, 0, 0, 0, WIDTH, HEIGHT,
+ GDK_PIXBUF_ALPHA_FULL, /* ignored */
+ 0x80, /* ignored */
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+ gdk_pixbuf_unref (pixbuf);
+ }
+ gdk_flush ();
+ total_time = g_timer_elapsed (timer, NULL) - start_time;
+
+ if (to_pixmap)
+ gdk_window_end_paint (drawing_area->window);
+
+ g_print ("Alpha test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n",
+ to_pixmap ? " (to pixmap)" : "",
+ total_time,
+ NUM_ITERS / total_time,
+ NUM_ITERS * (WIDTH * HEIGHT * 1e-6) / total_time);
+ }
+
g_print ("Please submit these results to http://www.levien.com/gdkrgb/survey.html\n");
#if 1