diff options
Diffstat (limited to 'libnautilus-extensions/nautilus-gdk-pixbuf-extensions.c')
-rw-r--r-- | libnautilus-extensions/nautilus-gdk-pixbuf-extensions.c | 1572 |
1 files changed, 0 insertions, 1572 deletions
diff --git a/libnautilus-extensions/nautilus-gdk-pixbuf-extensions.c b/libnautilus-extensions/nautilus-gdk-pixbuf-extensions.c deleted file mode 100644 index 8a0b81ad4..000000000 --- a/libnautilus-extensions/nautilus-gdk-pixbuf-extensions.c +++ /dev/null @@ -1,1572 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* nautilus-gdk-pixbuf-extensions.c: Routines to augment what's in gdk-pixbuf. - - Copyright (C) 2000 Eazel, Inc. - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Authors: Darin Adler <darin@eazel.com> - Ramiro Estrugo <ramiro@eazel.com> -*/ - -#include <config.h> -#include "nautilus-gdk-pixbuf-extensions.h" - -#include "nautilus-gdk-extensions.h" -#include "nautilus-glib-extensions.h" -#include "nautilus-string.h" -#include "nautilus-art-gtk-extensions.h" -#include "nautilus-lib-self-check-functions.h" -#include "nautilus-debug-drawing.h" -#include <gdk-pixbuf/gdk-pixbuf-loader.h> -#include <gdk/gdkx.h> -#include <gdk/gdkprivate.h> -#include <libgnomevfs/gnome-vfs-async-ops.h> -#include <libgnomevfs/gnome-vfs-ops.h> -#include <libgnomevfs/gnome-vfs-utils.h> -#include <math.h> -#include <png.h> - -#define LOAD_BUFFER_SIZE 4096 - -struct NautilusPixbufLoadHandle { - GnomeVFSAsyncHandle *vfs_handle; - NautilusPixbufLoadCallback callback; - gpointer callback_data; - GdkPixbufLoader *loader; - char buffer[LOAD_BUFFER_SIZE]; -}; - -static void file_opened_callback (GnomeVFSAsyncHandle *vfs_handle, - GnomeVFSResult result, - gpointer callback_data); -static void file_read_callback (GnomeVFSAsyncHandle *vfs_handle, - GnomeVFSResult result, - gpointer buffer, - GnomeVFSFileSize bytes_requested, - GnomeVFSFileSize bytes_read, - gpointer callback_data); -static void file_closed_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - gpointer callback_data); -static void load_done (NautilusPixbufLoadHandle *handle, - GnomeVFSResult result, - gboolean get_pixbuf); - -/** - * nautilus_gdk_pixbuf_list_ref - * @pixbuf_list: A list of GdkPixbuf objects. - * - * Refs all the pixbufs. - **/ -void -nautilus_gdk_pixbuf_list_ref (GList *pixbuf_list) -{ - g_list_foreach (pixbuf_list, (GFunc) gdk_pixbuf_ref, NULL); -} - -/** - * nautilus_gdk_pixbuf_list_free - * @pixbuf_list: A list of GdkPixbuf objects. - * - * Unrefs all the pixbufs, then frees the list. - **/ -void -nautilus_gdk_pixbuf_list_free (GList *pixbuf_list) -{ - nautilus_g_list_free_deep_custom (pixbuf_list, (GFunc) gdk_pixbuf_unref, NULL); -} - -GdkPixbuf * -nautilus_gdk_pixbuf_load (const char *uri) -{ - GnomeVFSResult result; - GnomeVFSHandle *handle; - char buffer[LOAD_BUFFER_SIZE]; - GnomeVFSFileSize bytes_read; - GdkPixbufLoader *loader; - GdkPixbuf *pixbuf; - - g_return_val_if_fail (uri != NULL, NULL); - - result = gnome_vfs_open (&handle, - uri, - GNOME_VFS_OPEN_READ); - if (result != GNOME_VFS_OK) { - return NULL; - } - - loader = gdk_pixbuf_loader_new (); - while (1) { - result = gnome_vfs_read (handle, - buffer, - sizeof (buffer), - &bytes_read); - if (result != GNOME_VFS_OK) { - break; - } - if (bytes_read == 0) { - break; - } - if (!gdk_pixbuf_loader_write (loader, - buffer, - bytes_read)) { - result = GNOME_VFS_ERROR_WRONG_FORMAT; - break; - } - } - - if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) { - gtk_object_unref (GTK_OBJECT (loader)); - gnome_vfs_close (handle); - return NULL; - } - - gnome_vfs_close (handle); - gdk_pixbuf_loader_close (loader); - - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - if (pixbuf != NULL) { - gdk_pixbuf_ref (pixbuf); - } - gtk_object_unref (GTK_OBJECT (loader)); - - return pixbuf; -} - -NautilusPixbufLoadHandle * -nautilus_gdk_pixbuf_load_async (const char *uri, - NautilusPixbufLoadCallback callback, - gpointer callback_data) -{ - NautilusPixbufLoadHandle *handle; - - handle = g_new0 (NautilusPixbufLoadHandle, 1); - handle->callback = callback; - handle->callback_data = callback_data; - - gnome_vfs_async_open (&handle->vfs_handle, - uri, - GNOME_VFS_OPEN_READ, - file_opened_callback, - handle); - - return handle; -} - -static void -file_opened_callback (GnomeVFSAsyncHandle *vfs_handle, - GnomeVFSResult result, - gpointer callback_data) -{ - NautilusPixbufLoadHandle *handle; - - handle = callback_data; - g_assert (handle->vfs_handle == vfs_handle); - - if (result != GNOME_VFS_OK) { - handle->vfs_handle = NULL; - load_done (handle, result, FALSE); - return; - } - - handle->loader = gdk_pixbuf_loader_new (); - - gnome_vfs_async_read (handle->vfs_handle, - handle->buffer, - sizeof (handle->buffer), - file_read_callback, - handle); -} - -static void -file_read_callback (GnomeVFSAsyncHandle *vfs_handle, - GnomeVFSResult result, - gpointer buffer, - GnomeVFSFileSize bytes_requested, - GnomeVFSFileSize bytes_read, - gpointer callback_data) -{ - NautilusPixbufLoadHandle *handle; - - handle = callback_data; - g_assert (handle->vfs_handle == vfs_handle); - g_assert (handle->buffer == buffer); - - if (result == GNOME_VFS_OK && bytes_read != 0) { - if (!gdk_pixbuf_loader_write (handle->loader, - buffer, - bytes_read)) { - result = GNOME_VFS_ERROR_WRONG_FORMAT; - } - gnome_vfs_async_read (handle->vfs_handle, - handle->buffer, - sizeof (handle->buffer), - file_read_callback, - handle); - return; - } - - load_done (handle, result, result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_EOF); -} - -static void -file_closed_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - gpointer callback_data) -{ - g_assert (callback_data == NULL); -} - -static void -free_pixbuf_load_handle (NautilusPixbufLoadHandle *handle) -{ - if (handle->loader != NULL) { - gtk_object_unref (GTK_OBJECT (handle->loader)); - } - g_free (handle); -} - -static void -load_done (NautilusPixbufLoadHandle *handle, GnomeVFSResult result, gboolean get_pixbuf) -{ - GdkPixbuf *pixbuf; - - if (handle->loader != NULL) { - gdk_pixbuf_loader_close (handle->loader); - } - - pixbuf = get_pixbuf ? gdk_pixbuf_loader_get_pixbuf (handle->loader) : NULL; - - if (handle->vfs_handle != NULL) { - gnome_vfs_async_close (handle->vfs_handle, file_closed_callback, NULL); - } - - handle->callback (result, pixbuf, handle->callback_data); - - free_pixbuf_load_handle (handle); -} - -void -nautilus_cancel_gdk_pixbuf_load (NautilusPixbufLoadHandle *handle) -{ - if (handle == NULL) { - return; - } - if (handle->vfs_handle != NULL) { - gnome_vfs_async_cancel (handle->vfs_handle); - } - free_pixbuf_load_handle (handle); -} - -/* return the average value of each component */ -void -nautilus_gdk_pixbuf_average_value (GdkPixbuf *pixbuf, GdkColor *color) -{ - uint red_total, green_total, blue_total, count; - int row, column; - int width, height; - int row_stride; - guchar *pixsrc, *original_pixels; - - gboolean has_alpha; - - red_total = 0; - green_total = 0; - blue_total = 0; - count = 0; - - /* iterate through the pixbuf, counting up each component */ - has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - row_stride = gdk_pixbuf_get_rowstride (pixbuf); - original_pixels = gdk_pixbuf_get_pixels (pixbuf); - - for (row = 0; row < height; row++) { - pixsrc = original_pixels + (row * row_stride); - for (column = 0; column < width; column++) { - red_total += *pixsrc++; - green_total += *pixsrc++; - blue_total += *pixsrc++; - count += 1; - if (has_alpha) { - pixsrc++; - } - } - } - - color->red = (red_total * 256) / count; - color->green = (green_total * 256) / count; - color->blue = (blue_total * 256) / count; -} - -double -nautilus_gdk_scale_to_fit_factor (int width, int height, - int max_width, int max_height, - int *scaled_width, int *scaled_height) -{ - double scale_factor; - - scale_factor = MIN (max_width / (double) width, max_height / (double) height); - - *scaled_width = floor (width * scale_factor + .5); - *scaled_height = floor (height * scale_factor + .5); - - return scale_factor; -} - -/* Returns a scaled copy of pixbuf, preserving aspect ratio. The copy will - * be scaled as large as possible without exceeding the specified width and height. - */ -GdkPixbuf * -nautilus_gdk_pixbuf_scale_to_fit (GdkPixbuf *pixbuf, int max_width, int max_height) -{ - int scaled_width; - int scaled_height; - - nautilus_gdk_scale_to_fit_factor (gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), - max_width, max_height, - &scaled_width, &scaled_height); - - return gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height, GDK_INTERP_BILINEAR); -} - -/* Returns a copy of pixbuf scaled down, preserving aspect ratio, to fit - * within the specified width and height. If it already fits, a copy of - * the original, without scaling, is returned. - */ -GdkPixbuf * -nautilus_gdk_pixbuf_scale_down_to_fit (GdkPixbuf *pixbuf, int max_width, int max_height) -{ - int scaled_width; - int scaled_height; - - double scale_factor; - - scale_factor = nautilus_gdk_scale_to_fit_factor (gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), - max_width, max_height, - &scaled_width, &scaled_height); - - if (scale_factor >= 1.0) { - return gdk_pixbuf_copy (pixbuf); - } else { - return gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height, GDK_INTERP_BILINEAR); - } -} - -/** - * nautilus_gdk_pixbuf_is_valid: - * @pixbuf: A GdkPixbuf - * - * Return value: A boolean indicating whether the given pixbuf is valid. - * - * A pixbuf is valid if: - * - * 1. It is non NULL - * 2. It is has non NULL pixel data. - * 3. It has width and height greater than 0. - */ -gboolean -nautilus_gdk_pixbuf_is_valid (const GdkPixbuf *pixbuf) -{ - return ((pixbuf != NULL) - && (gdk_pixbuf_get_pixels (pixbuf) != NULL) - && (gdk_pixbuf_get_width (pixbuf) > 0) - && (gdk_pixbuf_get_height (pixbuf) > 0)); -} - -/** - * nautilus_gdk_pixbuf_get_dimensions: - * @pixbuf: A GdkPixbuf - * - * Return value: The dimensions of the pixbuf as a NautilusDimensions. - * - * This function is useful in code that uses libart rect - * intersection routines. - */ -NautilusDimensions -nautilus_gdk_pixbuf_get_dimensions (const GdkPixbuf *pixbuf) -{ - NautilusDimensions dimensions; - - g_return_val_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf), NAUTILUS_DIMENSIONS_EMPTY); - - dimensions.width = gdk_pixbuf_get_width (pixbuf); - dimensions.height = gdk_pixbuf_get_height (pixbuf); - - return dimensions; -} - -/** - * nautilus_gdk_pixbuf_fill_rectangle: - * @pixbuf: Target pixbuf to fill into. - * @area: Rectangle to fill. - * @color: The color to use. - * - * Fill the rectangle with the the given color. - * Use the given rectangle if not NULL. - * If rectangle is NULL, fill the whole pixbuf. - */ -void -nautilus_gdk_pixbuf_fill_rectangle_with_color (GdkPixbuf *pixbuf, - const ArtIRect *area, - guint32 color) -{ - ArtIRect target; - guchar red; - guchar green; - guchar blue; - guchar alpha; - guchar *pixels; - gboolean has_alpha; - guint pixel_offset; - guint rowstride; - guchar *row_offset; - int x; - int y; - - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - - target = nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, area); - if (art_irect_empty (&target)) { - return; - } - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); - pixel_offset = has_alpha ? 4 : 3; - red = NAUTILUS_RGBA_COLOR_GET_R (color); - green = NAUTILUS_RGBA_COLOR_GET_G (color); - blue = NAUTILUS_RGBA_COLOR_GET_B (color); - alpha = NAUTILUS_RGBA_COLOR_GET_A (color); - - row_offset = pixels + target.y0 * rowstride; - - for (y = target.y0; y < target.y1; y++) { - guchar *offset = row_offset + (target.x0 * pixel_offset); - - for (x = target.x0; x < target.x1; x++) { - *(offset++) = red; - *(offset++) = green; - *(offset++) = blue; - - if (has_alpha) { - *(offset++) = alpha; - } - - } - - row_offset += rowstride; - } -} - -/* utility routine for saving a pixbuf to a png file. - * This was adapted from Iain Holmes' code in gnome-iconedit, and probably - * should be in a utility library, possibly in gdk-pixbuf itself. - */ -gboolean -nautilus_gdk_pixbuf_save_to_file (const GdkPixbuf *pixbuf, - const char *file_name) -{ - FILE *handle; - char *buffer; - gboolean has_alpha; - int width, height, depth, rowstride; - guchar *pixels; - png_structp png_ptr; - png_infop info_ptr; - png_text text[2]; - int i; - - g_return_val_if_fail (pixbuf != NULL, FALSE); - g_return_val_if_fail (file_name != NULL, FALSE); - g_return_val_if_fail (file_name[0] != '\0', FALSE); - - handle = fopen (file_name, "wb"); - if (handle == NULL) { - return FALSE; - } - - png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { - fclose (handle); - return FALSE; - } - - info_ptr = png_create_info_struct (png_ptr); - if (info_ptr == NULL) { - png_destroy_write_struct (&png_ptr, (png_infopp)NULL); - fclose (handle); - return FALSE; - } - - if (setjmp (png_ptr->jmpbuf)) { - png_destroy_write_struct (&png_ptr, &info_ptr); - fclose (handle); - return FALSE; - } - - png_init_io (png_ptr, handle); - - has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - depth = gdk_pixbuf_get_bits_per_sample (pixbuf); - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - - png_set_IHDR (png_ptr, info_ptr, width, height, - depth, PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - /* Some text to go with the png image */ - text[0].key = "Title"; - text[0].text = (char *) file_name; - text[0].compression = PNG_TEXT_COMPRESSION_NONE; - text[1].key = "Software"; - text[1].text = "Nautilus Thumbnail"; - text[1].compression = PNG_TEXT_COMPRESSION_NONE; - png_set_text (png_ptr, info_ptr, text, 2); - - /* Write header data */ - png_write_info (png_ptr, info_ptr); - - /* if there is no alpha in the data, allocate buffer to expand into */ - if (has_alpha) { - buffer = NULL; - } else { - buffer = g_malloc(4 * width); - } - - /* pump the raster data into libpng, one scan line at a time */ - for (i = 0; i < height; i++) { - if (has_alpha) { - png_bytep row_pointer = pixels; - png_write_row (png_ptr, row_pointer); - } else { - /* expand RGB to RGBA using an opaque alpha value */ - int x; - char *buffer_ptr = buffer; - char *source_ptr = pixels; - for (x = 0; x < width; x++) { - *buffer_ptr++ = *source_ptr++; - *buffer_ptr++ = *source_ptr++; - *buffer_ptr++ = *source_ptr++; - *buffer_ptr++ = 255; - } - png_write_row (png_ptr, (png_bytep) buffer); - } - pixels += rowstride; - } - - png_write_end (png_ptr, info_ptr); - png_destroy_write_struct (&png_ptr, &info_ptr); - - g_free (buffer); - - fclose (handle); - return TRUE; -} - -void -nautilus_gdk_pixbuf_ref_if_not_null (GdkPixbuf *pixbuf_or_null) -{ - if (pixbuf_or_null != NULL) { - gdk_pixbuf_ref (pixbuf_or_null); - } -} - -void -nautilus_gdk_pixbuf_unref_if_not_null (GdkPixbuf *pixbuf_or_null) -{ - if (pixbuf_or_null != NULL) { - gdk_pixbuf_unref (pixbuf_or_null); - } -} - -void -nautilus_gdk_pixbuf_draw_to_drawable (const GdkPixbuf *pixbuf, - GdkDrawable *drawable, - GdkGC *gc, - int source_x, - int source_y, - const ArtIRect *destination_area, - GdkRgbDither dither, - GdkPixbufAlphaMode alpha_compositing_mode, - int alpha_threshold) -{ - NautilusDimensions dimensions; - ArtIRect target; - ArtIRect source; - int target_width; - int target_height; - int source_width; - int source_height; - - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - g_return_if_fail (drawable != NULL); - g_return_if_fail (gc != NULL); - g_return_if_fail (destination_area != NULL); - g_return_if_fail (destination_area->x1 > destination_area->x0); - g_return_if_fail (destination_area->y1 > destination_area->y0); - g_return_if_fail (alpha_threshold > NAUTILUS_OPACITY_FULLY_TRANSPARENT); - g_return_if_fail (alpha_threshold <= NAUTILUS_OPACITY_FULLY_OPAQUE); - g_return_if_fail (alpha_compositing_mode >= GDK_PIXBUF_ALPHA_BILEVEL); - g_return_if_fail (alpha_compositing_mode <= GDK_PIXBUF_ALPHA_FULL); - - dimensions = nautilus_gdk_pixbuf_get_dimensions (pixbuf); - - g_return_if_fail (source_x >= 0); - g_return_if_fail (source_y >= 0); - g_return_if_fail (source_x < dimensions.width); - g_return_if_fail (source_y < dimensions.height); - - /* Clip the destination area to the pixbuf dimensions; bail if no work */ - target = nautilus_gdk_pixbuf_intersect (pixbuf, - destination_area->x0, - destination_area->y0, - destination_area); - if (art_irect_empty (&target)) { - return; - } - - /* Assign the source area */ - nautilus_art_irect_assign (&source, - source_x, - source_y, - dimensions.width - source_x, - dimensions.height - source_y); - - /* Adjust the target width if the source area is smaller than the - * source pixbuf dimensions */ - target_width = target.x1 - target.x0; - target_height = target.y1 - target.y0; - source_width = source.x1 - source.x0; - source_height = source.y1 - source.y0; - - target.x1 = target.x0 + MIN (target_width, source_width); - target.y1 = target.y0 + MIN (target_height, source_height); - - if (gdk_pixbuf_get_has_alpha (pixbuf)) { - gdk_pixbuf_render_to_drawable_alpha ((GdkPixbuf *) pixbuf, - drawable, - source.x0, - source.y0, - target.x0, - target.y0, - target.x1 - target.x0, - target.y1 - target.y0, - alpha_compositing_mode, - alpha_threshold, - dither, - 0, - 0); - } else { - gdk_pixbuf_render_to_drawable ((GdkPixbuf *) pixbuf, - drawable, - gc, - source.x0, - source.y0, - target.x0, - target.y0, - target.x1 - target.x0, - target.y1 - target.y0, - dither, - 0, - 0); - } -} - -/** - * nautilus_gdk_pixbuf_draw_to_pixbuf: - * @pixbuf: The source pixbuf to draw. - * @destination_pixbuf: The destination pixbuf. - * @source_x: The source pixbuf x coordiate to composite from. - * @source_y: The source pixbuf y coordiate to composite from. - * @destination_area: The destination area within the destination pixbuf. - * This area will be clipped if invalid in any way. - * - * Copy one pixbuf onto another another.. This function has some advantages - * over plain gdk_pixbuf_copy_area(): - * - * Composition paramters (source coordinate, destination area) are - * given in a way that is consistent with the rest of the extensions - * in this file. That is, it matches the declaration of - * nautilus_gdk_pixbuf_draw_to_pixbuf_alpha() and - * nautilus_gdk_pixbuf_draw_to_drawable() very closely. - * - * All values are clipped to make sure they are valid. - * - */ -void -nautilus_gdk_pixbuf_draw_to_pixbuf (const GdkPixbuf *pixbuf, - GdkPixbuf *destination_pixbuf, - int source_x, - int source_y, - const ArtIRect *destination_area) -{ - NautilusDimensions dimensions; - ArtIRect target; - ArtIRect source; - int target_width; - int target_height; - int source_width; - int source_height; - - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (destination_pixbuf)); - g_return_if_fail (destination_area != NULL); - g_return_if_fail (destination_area->x1 > destination_area->x0); - g_return_if_fail (destination_area->y1 > destination_area->y0); - - dimensions = nautilus_gdk_pixbuf_get_dimensions (pixbuf); - - g_return_if_fail (source_x >= 0); - g_return_if_fail (source_y >= 0); - g_return_if_fail (source_x < dimensions.width); - g_return_if_fail (source_y < dimensions.height); - - /* Clip the destination area to the pixbuf dimensions; bail if no work */ - target = nautilus_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); - if (art_irect_empty (&target)) { - return; - } - - /* Assign the source area */ - nautilus_art_irect_assign (&source, - source_x, - source_y, - dimensions.width - source_x, - dimensions.height - source_y); - - /* Adjust the target width if the source area is smaller than the - * source pixbuf dimensions */ - target_width = target.x1 - target.x0; - target_height = target.y1 - target.y0; - source_width = source.x1 - source.x0; - source_height = source.y1 - source.y0; - - target.x1 = target.x0 + MIN (target_width, source_width); - target.y1 = target.y0 + MIN (target_height, source_height); - - gdk_pixbuf_copy_area (pixbuf, - source.x0, - source.y0, - target.x1 - target.x0, - target.y1 - target.y0, - destination_pixbuf, - target.x0, - target.y0); -} - -/** - * nautilus_gdk_pixbuf_draw_to_pixbuf_alpha: - * @pixbuf: The source pixbuf to draw. - * @destination_pixbuf: The destination pixbuf. - * @source_x: The source pixbuf x coordiate to composite from. - * @source_y: The source pixbuf y coordiate to composite from. - * @destination_area: The destination area within the destination pixbuf. - * This area will be clipped if invalid in any way. - * @opacity: The opacity of the drawn tiles where 0 <= opacity <= 255. - * @interpolation_mode: The interpolation mode. See <gdk-pixbuf.h> - * - * Composite one pixbuf over another. This function has some advantages - * over plain gdk_pixbuf_composite(): - * - * Composition paramters (source coordinate, destination area) are - * given in a way that is consistent with the rest of the extensions - * in this file. That is, it matches the declaration of - * nautilus_gdk_pixbuf_draw_to_pixbuf() and - * nautilus_gdk_pixbuf_draw_to_drawable() very closely. - * - * All values are clipped to make sure they are valid. - * - * Workaround a limitation in gdk_pixbuf_composite() that does not allow - * the source (x,y) to be greater than (0,0) - * - */ -void -nautilus_gdk_pixbuf_draw_to_pixbuf_alpha (const GdkPixbuf *pixbuf, - GdkPixbuf *destination_pixbuf, - int source_x, - int source_y, - const ArtIRect *destination_area, - int opacity, - GdkInterpType interpolation_mode) -{ - NautilusDimensions dimensions; - ArtIRect target; - ArtIRect source; - int target_width; - int target_height; - int source_width; - int source_height; - - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (destination_pixbuf)); - g_return_if_fail (destination_area != NULL); - g_return_if_fail (destination_area->x1 > destination_area->x0); - g_return_if_fail (destination_area->y1 > destination_area->y0); - g_return_if_fail (opacity >= NAUTILUS_OPACITY_FULLY_TRANSPARENT); - g_return_if_fail (opacity <= NAUTILUS_OPACITY_FULLY_OPAQUE); - g_return_if_fail (interpolation_mode >= GDK_INTERP_NEAREST); - g_return_if_fail (interpolation_mode <= GDK_INTERP_HYPER); - - dimensions = nautilus_gdk_pixbuf_get_dimensions (pixbuf); - - g_return_if_fail (source_x >= 0); - g_return_if_fail (source_y >= 0); - g_return_if_fail (source_x < dimensions.width); - g_return_if_fail (source_y < dimensions.height); - - /* Clip the destination area to the pixbuf dimensions; bail if no work */ - /* Clip the destination area to the pixbuf dimensions; bail if no work */ - target = nautilus_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); - if (art_irect_empty (&target)) { - return; - } - - /* Assign the source area */ - nautilus_art_irect_assign (&source, - source_x, - source_y, - dimensions.width - source_x, - dimensions.height - source_y); - - /* Adjust the target width if the source area is smaller than the - * source pixbuf dimensions */ - target_width = target.x1 - target.x0; - target_height = target.y1 - target.y0; - source_width = source.x1 - source.x0; - source_height = source.y1 - source.y0; - - target.x1 = target.x0 + MIN (target_width, source_width); - target.y1 = target.y0 + MIN (target_height, source_height); - - /* If the source point is not (0,0), then we need to create a sub pixbuf - * with only the source area. This is needed to work around a limitation - * in gdk_pixbuf_composite() that requires the source area to be (0,0). */ - if (source.x0 != 0 || source.y0 != 0) { - ArtIRect area; - int width; - int height; - - width = dimensions.width - source.x0; - height = dimensions.height - source.y0; - - area.x0 = source.x0; - area.y0 = source.y0; - area.x1 = area.x0 + width; - area.y1 = area.y0 + height; - - pixbuf = nautilus_gdk_pixbuf_new_from_pixbuf_sub_area ((GdkPixbuf *) pixbuf, &area); - } else { - gdk_pixbuf_ref ((GdkPixbuf *) pixbuf); - } - - gdk_pixbuf_composite (pixbuf, - destination_pixbuf, - target.x0, - target.y0, - target.x1 - target.x0, - target.y1 - target.y0, - target.x0, - target.y0, - 1.0, - 1.0, - interpolation_mode, - opacity); - - gdk_pixbuf_unref ((GdkPixbuf *) pixbuf); -} - -static void -pixbuf_destroy_callback (guchar *pixels, - gpointer callback_data) -{ - g_return_if_fail (pixels != NULL); - g_return_if_fail (callback_data != NULL); - - gdk_pixbuf_unref ((GdkPixbuf *) callback_data); -} - -/** - * nautilus_gdk_pixbuf_new_from_pixbuf_sub_area: - * @pixbuf: The source pixbuf. - * @area: The area within the source pixbuf to use for the sub pixbuf. - * This area needs to be contained within the bounds of the - * source pixbuf, otherwise it will be clipped to that. - * - * Return value: A newly allocated pixbuf that shares the pixel data - * of the source pixbuf in order to represent a sub area. - * - * Create a pixbuf from a sub area of another pixbuf. The resulting pixbuf - * will share the pixel data of the source pixbuf. Memory bookeeping is - * all taken care for the caller. All you need to do is gdk_pixbuf_unref() - * the resulting pixbuf to properly free resources. - */ -GdkPixbuf * -nautilus_gdk_pixbuf_new_from_pixbuf_sub_area (GdkPixbuf *pixbuf, - const ArtIRect *area) -{ - GdkPixbuf *sub_pixbuf; - ArtIRect target; - guchar *pixels; - - g_return_val_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf), NULL); - g_return_val_if_fail (area != NULL, NULL); - g_return_val_if_fail (area->x1 > area->x0, NULL); - g_return_val_if_fail (area->y1 > area->y0, NULL); - - /* Clip the pixbuf by the given area; bail if no work */ - target = nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, area); - if (art_irect_empty (&target)) { - return NULL; - } - - /* Since we are going to be sharing the given pixbuf's data, we need - * to ref it. It will be unreffed in the destroy function above */ - gdk_pixbuf_ref (pixbuf); - - /* Compute the offset into the pixel data */ - pixels = - gdk_pixbuf_get_pixels (pixbuf) - + (target.y0 * gdk_pixbuf_get_rowstride (pixbuf)) - + (target.x0 * (gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3)); - - /* Make a pixbuf pretending its real estate is the sub area */ - sub_pixbuf = gdk_pixbuf_new_from_data (pixels, - GDK_COLORSPACE_RGB, - gdk_pixbuf_get_has_alpha (pixbuf), - 8, - nautilus_art_irect_get_width (&target), - nautilus_art_irect_get_height (&target), - gdk_pixbuf_get_rowstride (pixbuf), - pixbuf_destroy_callback, - pixbuf); - - return sub_pixbuf; -} - -/** - * nautilus_gdk_pixbuf_new_from_existing_buffer: - * @buffer: The existing buffer. - * @buffer_rowstride: The existing buffer's rowstride. - * @buffer_has_alpha: A boolean value indicating whether the buffer has alpha. - * @area: The area within the existing buffer to use for the pixbuf. - * This area needs to be contained within the bounds of the - * buffer, otherwise memory will be trashed. - * - * Return value: A newly allocated pixbuf that uses the existing buffer - * for its pixel data. - * - * Create a pixbuf from an existing buffer. - * - * The resulting pixbuf is only valid for as long as &buffer is valid. It is - * up to the caller to make sure they both exist in the same scope. - * Also, it is up to the caller to make sure that the given area is fully - * contained in the buffer, otherwise memory trashing will happen. - */ -GdkPixbuf * -nautilus_gdk_pixbuf_new_from_existing_buffer (guchar *buffer, - int buffer_rowstride, - gboolean buffer_has_alpha, - const ArtIRect *area) -{ - GdkPixbuf *pixbuf; - guchar *pixels; - - g_return_val_if_fail (buffer != NULL, NULL); - g_return_val_if_fail (buffer_rowstride > 0, NULL); - g_return_val_if_fail (area != NULL, NULL); - g_return_val_if_fail (area->x1 > area->x0, NULL); - g_return_val_if_fail (area->y1 > area->y0, NULL); - - /* Compute the offset into the buffer */ - pixels = - buffer - + (area->y0 * buffer_rowstride) - + (area->x0 * (buffer_has_alpha ? 4 : 3)); - - pixbuf = gdk_pixbuf_new_from_data (pixels, - GDK_COLORSPACE_RGB, - buffer_has_alpha, - 8, - nautilus_art_irect_get_width (area), - nautilus_art_irect_get_height (area), - buffer_rowstride, - NULL, - NULL); - - return pixbuf; -} - -/* The tile algorithm is identical whether the destination is - * a pixbuf or a drawable. So, we use a simple callback - * mechanism to share it regardless of the destination. - */ -typedef struct { - GdkPixbuf *destination_pixbuf; - int opacity; - GdkInterpType interpolation_mode; -} PixbufTileData; - -typedef struct { - GdkDrawable *drawable; - GdkGC *gc; - GdkRgbDither dither; - GdkPixbufAlphaMode alpha_compositing_mode; - int alpha_threshold; -} DrawableTileData; - -typedef void (* DrawPixbufTileCallback) (const GdkPixbuf *pixbuf, - int x, - int y, - const ArtIRect *destination_area, - gpointer callback_data); - -/* The shared tiliing implementation */ -static void -pixbuf_draw_tiled (const GdkPixbuf *pixbuf, - const NautilusDimensions *destination_dimensions, - const ArtIRect *destination_area, - int tile_width, - int tile_height, - int tile_origin_x, - int tile_origin_y, - DrawPixbufTileCallback callback, - gpointer callback_data) -{ - ArtIRect target; - int x; - int y; - NautilusArtIPoint min_point; - NautilusArtIPoint max_point; - int num_left; - int num_above; - - g_return_if_fail (pixbuf != NULL); - g_return_if_fail (destination_dimensions != NULL); - g_return_if_fail (tile_width > 0); - g_return_if_fail (tile_height > 0); - g_return_if_fail (tile_width <= gdk_pixbuf_get_width (pixbuf)); - g_return_if_fail (tile_height <= gdk_pixbuf_get_height (pixbuf)); - g_return_if_fail (callback != NULL); - - /* FIXME: This is confusing. Instead of passing in the destination_dimensions - * I should just pass in the destination pixbuf, so that we can use - * nautilus_gdk_pixbuf_intersect directly on that. - */ - - /* Clip the destination area to the destination pixbuf; bail if no work */ - if (destination_area != NULL) { - ArtIRect tmp; - - tmp = nautilus_art_irect_assign_dimensions (0, 0, destination_dimensions); - art_irect_intersect (&target, destination_area, &tmp); - - if (art_irect_empty (&target)) { - return; - } - } else { - target = nautilus_art_irect_assign_dimensions (0, 0, destination_dimensions); - } - - /* The number of tiles left and above the target area */ - num_left = (target.x0 - tile_origin_x) / tile_width; - num_above = (target.y0 - tile_origin_y) / tile_height; - - min_point.x = tile_origin_x - tile_width + (num_left * tile_width); - min_point.y = tile_origin_y - tile_height + (num_above * tile_height); - - max_point.x = (target.x1 + 2 * tile_width); - max_point.y = (target.y1 + 2 * tile_height); - - for (y = min_point.y; y <= max_point.y; y += tile_height) { - for (x = min_point.x; x <= max_point.x; x += tile_width) { - ArtIRect current; - ArtIRect area; - - nautilus_art_irect_assign (¤t, x, y, tile_width, tile_height); - - /* FIXME: A potential speed improvement here would be to clip only the - * first and last rectangles, not the ones in between. - */ - art_irect_intersect (&area, &target, ¤t); - - if (!art_irect_empty (&area)) { - g_assert (area.x0 >= x); - g_assert (area.y0 >= y); - - (* callback) (pixbuf, - area.x0 - x, - area.y0 - y, - &area, - callback_data); - } - } - } -} - -static void -draw_tile_to_pixbuf_callback (const GdkPixbuf *pixbuf, - int x, - int y, - const ArtIRect *area, - gpointer callback_data) -{ - PixbufTileData *pixbuf_tile_data; - - g_return_if_fail (pixbuf != NULL); - g_return_if_fail (area != NULL); - g_return_if_fail (callback_data != NULL); - - pixbuf_tile_data = (PixbufTileData *) callback_data; - - if (pixbuf_tile_data->opacity == NAUTILUS_OPACITY_FULLY_TRANSPARENT) { - nautilus_gdk_pixbuf_draw_to_pixbuf (pixbuf, - pixbuf_tile_data->destination_pixbuf, - x, - y, - area); - } else { - nautilus_gdk_pixbuf_draw_to_pixbuf_alpha (pixbuf, - pixbuf_tile_data->destination_pixbuf, - x, - y, - area, - pixbuf_tile_data->opacity, - pixbuf_tile_data->interpolation_mode); - } -} - -static void -draw_tile_to_drawable_callback (const GdkPixbuf *pixbuf, - int x, - int y, - const ArtIRect *area, - gpointer callback_data) -{ - DrawableTileData *drawable_tile_data; - - g_return_if_fail (pixbuf != NULL); - g_return_if_fail (area != NULL); - g_return_if_fail (callback_data != NULL); - - drawable_tile_data = (DrawableTileData *) callback_data; - - nautilus_gdk_pixbuf_draw_to_drawable (pixbuf, - drawable_tile_data->drawable, - drawable_tile_data->gc, - x, - y, - area, - drawable_tile_data->dither, - drawable_tile_data->alpha_compositing_mode, - drawable_tile_data->alpha_threshold); -} - -/** - * nautilus_gdk_pixbuf_draw_to_pixbuf_tiled: - * @pixbuf: Source tile pixbuf. - * @destination_pixbuf: Destination pixbuf. - * @destination_area: Area of the destination pixbuf to tile. - * @tile_width: Width of the tile. This can be less than width of the - * tile pixbuf, but not greater. - * @tile_height: Height of the tile. This can be less than width of the - * tile pixbuf, but not greater. - * @tile_origin_x: The x coordinate of the tile origin. Can be negative. - * @tile_origin_y: The y coordinate of the tile origin. Can be negative. - * @opacity: The opacity of the drawn tiles where 0 <= opacity <= 255. - * @interpolation_mode: The interpolation mode. See <gdk-pixbuf.h> - * - * Fill an area of a GdkPixbuf with a tile. - */ -void -nautilus_gdk_pixbuf_draw_to_pixbuf_tiled (const GdkPixbuf *pixbuf, - GdkPixbuf *destination_pixbuf, - const ArtIRect *destination_area, - int tile_width, - int tile_height, - int tile_origin_x, - int tile_origin_y, - int opacity, - GdkInterpType interpolation_mode) -{ - PixbufTileData pixbuf_tile_data; - NautilusDimensions destination_dimensions; - - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (destination_pixbuf)); - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - g_return_if_fail (tile_width > 0); - g_return_if_fail (tile_height > 0); - g_return_if_fail (tile_width <= gdk_pixbuf_get_width (pixbuf)); - g_return_if_fail (tile_height <= gdk_pixbuf_get_height (pixbuf)); - g_return_if_fail (opacity >= NAUTILUS_OPACITY_FULLY_TRANSPARENT); - g_return_if_fail (opacity <= NAUTILUS_OPACITY_FULLY_OPAQUE); - g_return_if_fail (interpolation_mode >= GDK_INTERP_NEAREST); - g_return_if_fail (interpolation_mode <= GDK_INTERP_HYPER); - - destination_dimensions = nautilus_gdk_pixbuf_get_dimensions (destination_pixbuf); - - pixbuf_tile_data.destination_pixbuf = destination_pixbuf; - pixbuf_tile_data.opacity = opacity; - pixbuf_tile_data.interpolation_mode = interpolation_mode; - - pixbuf_draw_tiled (pixbuf, - &destination_dimensions, - destination_area, - tile_width, - tile_height, - tile_origin_x, - tile_origin_y, - draw_tile_to_pixbuf_callback, - &pixbuf_tile_data); -} - -/** - * nautilus_gdk_pixbuf_draw_to_drawable_tiled: - * @pixbuf: Source tile pixbuf. - * @gc: GC for copy area operation. - * @drawable: Destination drawable. - * @destination_area: Area of the destination pixbuf to tile. - * @tile_width: Width of the tile. This can be less than width of the - * tile pixbuf, but not greater. - * @tile_height: Height of the tile. This can be less than width of the - * tile pixbuf, but not greater. - * @tile_origin_x: The x coordinate of the tile origin. Can be negative. - * @tile_origin_y: The y coordinate of the tile origin. Can be negative. - * @dither: Dither type to use (see <gdkrgb.h>) - * @dither: Dither type to use (see <gdkrgb.h>) - * @alpha_compositing_mode: The alpha compositing mode. See <gdk-pixbuf.h> - * - * Fill an area of a GdkDrawable with a tile. - */ -void -nautilus_gdk_pixbuf_draw_to_drawable_tiled (const GdkPixbuf *pixbuf, - GdkDrawable *drawable, - GdkGC *gc, - const ArtIRect *destination_area, - int tile_width, - int tile_height, - int tile_origin_x, - int tile_origin_y, - GdkRgbDither dither, - GdkPixbufAlphaMode alpha_compositing_mode, - int alpha_threshold) -{ - DrawableTileData drawable_tile_data; - NautilusDimensions destination_dimensions; - - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - g_return_if_fail (drawable != NULL); - g_return_if_fail (tile_width > 0); - g_return_if_fail (tile_height > 0); - g_return_if_fail (tile_width <= gdk_pixbuf_get_width (pixbuf)); - g_return_if_fail (tile_height <= gdk_pixbuf_get_height (pixbuf)); - g_return_if_fail (alpha_threshold > NAUTILUS_OPACITY_FULLY_TRANSPARENT); - g_return_if_fail (alpha_threshold <= NAUTILUS_OPACITY_FULLY_OPAQUE); - g_return_if_fail (alpha_compositing_mode >= GDK_PIXBUF_ALPHA_BILEVEL); - g_return_if_fail (alpha_compositing_mode <= GDK_PIXBUF_ALPHA_FULL); - - destination_dimensions = nautilus_gdk_window_get_dimensions (drawable); - - drawable_tile_data.drawable = drawable; - drawable_tile_data.gc = gc; - drawable_tile_data.dither = dither; - drawable_tile_data.alpha_compositing_mode = alpha_compositing_mode; - drawable_tile_data.alpha_threshold = alpha_threshold; - - pixbuf_draw_tiled (pixbuf, - &destination_dimensions, - destination_area, - tile_width, - tile_height, - tile_origin_x, - tile_origin_y, - draw_tile_to_drawable_callback, - &drawable_tile_data); -} - -/** - * nautilus_gdk_pixbuf_get_global_buffer: - * @minimum_width: The minimum width for the requested buffer. - * @minimum_height: The minimum height for the requested buffer. - * - * Return value: A GdkPixbuf that is at least as big as the passed in - * dimensions. - * - * Access a global buffer for temporary GdkPixbuf operations. - * The returned buffer will be at least as big as the passed in - * dimensions. The contents are not guaranteed to be anything at - * anytime. Also, it is not thread safe at all. */ - -static GdkPixbuf *global_buffer = NULL; - -static void -destroy_global_buffer (void) -{ - if (global_buffer != NULL) { - gdk_pixbuf_unref (global_buffer); - global_buffer = NULL; - } -} - -GdkPixbuf * -nautilus_gdk_pixbuf_get_global_buffer (int minimum_width, - int minimum_height) -{ - static gboolean at_exit_deallocator_installed = FALSE; - - g_return_val_if_fail (minimum_width > 0, NULL); - g_return_val_if_fail (minimum_height > 0, NULL); - - if (global_buffer != NULL) { - if (gdk_pixbuf_get_width (global_buffer) >= minimum_width - && gdk_pixbuf_get_height (global_buffer) >= minimum_height) { - return global_buffer; - } - - destroy_global_buffer (); - } - - g_assert (global_buffer == NULL); - - global_buffer = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, - minimum_width, minimum_height); - - - if (at_exit_deallocator_installed == FALSE) { - at_exit_deallocator_installed = TRUE; - g_atexit (destroy_global_buffer); - } - - return global_buffer; -} - -/* Same as gdk_pixbuf_get_from_drawable() except it deals with - * race conditions and other evil things that can happen */ -GdkPixbuf * -nautilus_gdk_pixbuf_get_from_window_safe (GdkWindow *window, - int x, - int y, - int width, - int height) -{ - GdkWindowPrivate *window_private; - GdkPixbuf *pixbuf; - int error_code; - GdkWindowType save_window_type; - GdkColormap *colormap; - - g_return_val_if_fail (window != NULL, NULL); - - - /* Push an error handler so that we can catch - * the very rare (but possible) case where - * the GetImage() request fails. See HACK2 below - * for a more complete excuse. - */ - gdk_error_trap_push (); - - /* Save the window type and colormap. Otherwise - * GdkPixbuf will try to fetch them from a hacked - * window. See HACK1 below for reason why we - * hack the private window contents. - */ - save_window_type = gdk_window_get_type (window); - colormap = gdk_window_get_colormap (window); - - /* HACK1: - * - * This horrible thing we do here is needed to - * prevent GdkPixbuf from doing geometry sanity - * checks on the window. By pretending it - * is a Pixmap, we fool GdkPixbuf into not doing - * these checks. - * - * Why ? The sanity checks that GdkPixbuf does - * are good most of the time, but not 100% of - * the time. This is because there is no guarantee - * that when the x server gets the GetImage request, - * the geometry of that window is what GdkPixbuf - * thought it was. - * - * For example, the window manager could have triggered - * a sequence of events causing the window to resize. - */ - window_private = (GdkWindowPrivate*) window; - window_private->window_type = GDK_WINDOW_PIXMAP; - - pixbuf = gdk_pixbuf_get_from_drawable (NULL, - window, - colormap, - x, - y, - 0, - 0, - width, - height); - - /* Restore the window's guts */ - window_private->window_type = save_window_type; - - /* HACK2: - * - * Now we pop the error handler and see whether an error - * occured. - * - * It is very rare that an error might occur. The conditions - * under which it might are: - * - * 1) Race condition as described above in HACK1 - * - * 2) Bogus coordinates and/or dimensions given to - * the GetImage() request - which GdkPixbuf cant - * safely sanity check against. - * - * So, if we get an error, we simply drop this request on - * the floor and return NULL. The caller needs to deal with - * the fact that their request couldnt be executed. Most of - * the time, all that is needed is to simply ignore it. - */ - error_code = gdk_error_trap_pop (); - - if (error_code != 0) { - /* HACK3: - * - * The magical number "8" is the minor x error request - * code. That is the only error we are expecting. - * - * Otherwise we still return NULL, but the caller - * gets a critical. - */ - g_return_val_if_fail (error_code == 8, NULL); - - return NULL; - } - - return pixbuf; -} - -/** - * nautilus_gdk_pixbuf_intersect: - * @pixbuf: A GdkPixbuf. - * @pixbuf_x: X coordinate of pixbuf. - * @pixbuf_y: Y coordinate of pixbuf. - * @rectangle: An ArtIRect or NULL. - * - * Return value: The intersection of the pixbuf and the given rectangle. - * - * If &rectangle is NULL, then the resulting rectangle is a rectangle at - * the given orign with the pixbuf's dimensions. - * - */ -ArtIRect -nautilus_gdk_pixbuf_intersect (const GdkPixbuf *pixbuf, - int pixbuf_x, - int pixbuf_y, - const ArtIRect *rectangle) -{ - ArtIRect intersection; - ArtIRect bounds; - NautilusDimensions dimensions; - - g_return_val_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf), NAUTILUS_ART_IRECT_EMPTY); - - dimensions = nautilus_gdk_pixbuf_get_dimensions (pixbuf); - bounds = nautilus_art_irect_assign_dimensions (pixbuf_x, pixbuf_y, &dimensions); - - if (rectangle == NULL) { - return bounds; - } - - art_irect_intersect (&intersection, rectangle, &bounds); - - /* In theory, this is not needed because a rectangle is empty - * regardless of how MUCH negative the dimensions are. - * However, to make debugging and self checks simpler, we - * consistenly return a standard empty rectangle. - */ - if (art_irect_empty (&intersection)) { - return NAUTILUS_ART_IRECT_EMPTY; - } - - return intersection; -} - -#if !defined (NAUTILUS_OMIT_SELF_CHECK) - -void -nautilus_self_check_gdk_pixbuf_extensions (void) -{ - GdkPixbuf *pixbuf; - ArtIRect clip_area; - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 100, 100); - - NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_gdk_pixbuf_is_valid (pixbuf), TRUE); - NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_gdk_pixbuf_is_valid (NULL), FALSE); - - NAUTILUS_CHECK_DIMENSIONS_RESULT (nautilus_gdk_pixbuf_get_dimensions (pixbuf), 100, 100); - - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, NULL), 0, 0, 100, 100); - - nautilus_art_irect_assign (&clip_area, 0, 0, 0, 0); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 0, 0); - - nautilus_art_irect_assign (&clip_area, 0, 0, 0, 0); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 0, 0); - - nautilus_art_irect_assign (&clip_area, 0, 0, 100, 100); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 100, 100); - - nautilus_art_irect_assign (&clip_area, -10, -10, 100, 100); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 90, 90); - - nautilus_art_irect_assign (&clip_area, -10, -10, 110, 110); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 100, 100); - - nautilus_art_irect_assign (&clip_area, 0, 0, 99, 99); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 99, 99); - - nautilus_art_irect_assign (&clip_area, 0, 0, 1, 1); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 1, 1); - - nautilus_art_irect_assign (&clip_area, -1, -1, 1, 1); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 0, 0); - - nautilus_art_irect_assign (&clip_area, -1, -1, 2, 2); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 1, 1); - - nautilus_art_irect_assign (&clip_area, 100, 100, 1, 1); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 0, 0); - - nautilus_art_irect_assign (&clip_area, 101, 101, 1, 1); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 0, 0, 0, 0); - - nautilus_art_irect_assign (&clip_area, 80, 0, 100, 100); - NAUTILUS_CHECK_RECTANGLE_RESULT (nautilus_gdk_pixbuf_intersect (pixbuf, 0, 0, &clip_area), 80, 0, 100, 100); - - gdk_pixbuf_unref (pixbuf); -} - -#endif /* !NAUTILUS_OMIT_SELF_CHECK */ |