michael@0: /* michael@0: * Copyright © 2000 SuSE, Inc. michael@0: * Copyright © 2007 Red Hat, Inc. michael@0: * michael@0: * Permission to use, copy, modify, distribute, and sell this software and its michael@0: * documentation for any purpose is hereby granted without fee, provided that michael@0: * the above copyright notice appear in all copies and that both that michael@0: * copyright notice and this permission notice appear in supporting michael@0: * documentation, and that the name of SuSE not be used in advertising or michael@0: * publicity pertaining to distribution of the software without specific, michael@0: * written prior permission. SuSE makes no representations about the michael@0: * suitability of this software for any purpose. It is provided "as is" michael@0: * without express or implied warranty. michael@0: * michael@0: * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL michael@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE michael@0: * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION michael@0: * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN michael@0: * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. michael@0: */ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "pixman-private.h" michael@0: michael@0: static const pixman_color_t transparent_black = { 0, 0, 0, 0 }; michael@0: michael@0: static void michael@0: gradient_property_changed (pixman_image_t *image) michael@0: { michael@0: gradient_t *gradient = &image->gradient; michael@0: int n = gradient->n_stops; michael@0: pixman_gradient_stop_t *stops = gradient->stops; michael@0: pixman_gradient_stop_t *begin = &(gradient->stops[-1]); michael@0: pixman_gradient_stop_t *end = &(gradient->stops[n]); michael@0: michael@0: switch (gradient->common.repeat) michael@0: { michael@0: default: michael@0: case PIXMAN_REPEAT_NONE: michael@0: begin->x = INT32_MIN; michael@0: begin->color = transparent_black; michael@0: end->x = INT32_MAX; michael@0: end->color = transparent_black; michael@0: break; michael@0: michael@0: case PIXMAN_REPEAT_NORMAL: michael@0: begin->x = stops[n - 1].x - pixman_fixed_1; michael@0: begin->color = stops[n - 1].color; michael@0: end->x = stops[0].x + pixman_fixed_1; michael@0: end->color = stops[0].color; michael@0: break; michael@0: michael@0: case PIXMAN_REPEAT_REFLECT: michael@0: begin->x = - stops[0].x; michael@0: begin->color = stops[0].color; michael@0: end->x = pixman_int_to_fixed (2) - stops[n - 1].x; michael@0: end->color = stops[n - 1].color; michael@0: break; michael@0: michael@0: case PIXMAN_REPEAT_PAD: michael@0: begin->x = INT32_MIN; michael@0: begin->color = stops[0].color; michael@0: end->x = INT32_MAX; michael@0: end->color = stops[n - 1].color; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: pixman_bool_t michael@0: _pixman_init_gradient (gradient_t * gradient, michael@0: const pixman_gradient_stop_t *stops, michael@0: int n_stops) michael@0: { michael@0: return_val_if_fail (n_stops > 0, FALSE); michael@0: michael@0: /* We allocate two extra stops, one before the beginning of the stop list, michael@0: * and one after the end. These stops are initialized to whatever color michael@0: * would be used for positions outside the range of the stop list. michael@0: * michael@0: * This saves a bit of computation in the gradient walker. michael@0: * michael@0: * The pointer we store in the gradient_t struct still points to the michael@0: * first user-supplied struct, so when freeing, we will have to michael@0: * subtract one. michael@0: */ michael@0: gradient->stops = michael@0: pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t)); michael@0: if (!gradient->stops) michael@0: return FALSE; michael@0: michael@0: gradient->stops += 1; michael@0: memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t)); michael@0: gradient->n_stops = n_stops; michael@0: michael@0: gradient->common.property_changed = gradient_property_changed; michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: void michael@0: _pixman_image_init (pixman_image_t *image) michael@0: { michael@0: image_common_t *common = &image->common; michael@0: michael@0: pixman_region32_init (&common->clip_region); michael@0: michael@0: common->alpha_count = 0; michael@0: common->have_clip_region = FALSE; michael@0: common->clip_sources = FALSE; michael@0: common->transform = NULL; michael@0: common->repeat = PIXMAN_REPEAT_NONE; michael@0: common->filter = PIXMAN_FILTER_NEAREST; michael@0: common->filter_params = NULL; michael@0: common->n_filter_params = 0; michael@0: common->alpha_map = NULL; michael@0: common->component_alpha = FALSE; michael@0: common->ref_count = 1; michael@0: common->property_changed = NULL; michael@0: common->client_clip = FALSE; michael@0: common->destroy_func = NULL; michael@0: common->destroy_data = NULL; michael@0: common->dirty = TRUE; michael@0: } michael@0: michael@0: pixman_bool_t michael@0: _pixman_image_fini (pixman_image_t *image) michael@0: { michael@0: image_common_t *common = (image_common_t *)image; michael@0: michael@0: common->ref_count--; michael@0: michael@0: if (common->ref_count == 0) michael@0: { michael@0: if (image->common.destroy_func) michael@0: image->common.destroy_func (image, image->common.destroy_data); michael@0: michael@0: pixman_region32_fini (&common->clip_region); michael@0: michael@0: free (common->transform); michael@0: free (common->filter_params); michael@0: michael@0: if (common->alpha_map) michael@0: pixman_image_unref ((pixman_image_t *)common->alpha_map); michael@0: michael@0: if (image->type == LINEAR || michael@0: image->type == RADIAL || michael@0: image->type == CONICAL) michael@0: { michael@0: if (image->gradient.stops) michael@0: { michael@0: /* See _pixman_init_gradient() for an explanation of the - 1 */ michael@0: free (image->gradient.stops - 1); michael@0: } michael@0: michael@0: /* This will trigger if someone adds a property_changed michael@0: * method to the linear/radial/conical gradient overwriting michael@0: * the general one. michael@0: */ michael@0: assert ( michael@0: image->common.property_changed == gradient_property_changed); michael@0: } michael@0: michael@0: if (image->type == BITS && image->bits.free_me) michael@0: free (image->bits.free_me); michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: return FALSE; michael@0: } michael@0: michael@0: pixman_image_t * michael@0: _pixman_image_allocate (void) michael@0: { michael@0: pixman_image_t *image = malloc (sizeof (pixman_image_t)); michael@0: michael@0: if (image) michael@0: _pixman_image_init (image); michael@0: michael@0: return image; michael@0: } michael@0: michael@0: static void michael@0: image_property_changed (pixman_image_t *image) michael@0: { michael@0: image->common.dirty = TRUE; michael@0: } michael@0: michael@0: /* Ref Counting */ michael@0: PIXMAN_EXPORT pixman_image_t * michael@0: pixman_image_ref (pixman_image_t *image) michael@0: { michael@0: image->common.ref_count++; michael@0: michael@0: return image; michael@0: } michael@0: michael@0: /* returns TRUE when the image is freed */ michael@0: PIXMAN_EXPORT pixman_bool_t michael@0: pixman_image_unref (pixman_image_t *image) michael@0: { michael@0: if (_pixman_image_fini (image)) michael@0: { michael@0: free (image); michael@0: return TRUE; michael@0: } michael@0: michael@0: return FALSE; michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_destroy_function (pixman_image_t * image, michael@0: pixman_image_destroy_func_t func, michael@0: void * data) michael@0: { michael@0: image->common.destroy_func = func; michael@0: image->common.destroy_data = data; michael@0: } michael@0: michael@0: PIXMAN_EXPORT void * michael@0: pixman_image_get_destroy_data (pixman_image_t *image) michael@0: { michael@0: return image->common.destroy_data; michael@0: } michael@0: michael@0: void michael@0: _pixman_image_reset_clip_region (pixman_image_t *image) michael@0: { michael@0: image->common.have_clip_region = FALSE; michael@0: } michael@0: michael@0: /* Executive Summary: This function is a no-op that only exists michael@0: * for historical reasons. michael@0: * michael@0: * There used to be a bug in the X server where it would rely on michael@0: * out-of-bounds accesses when it was asked to composite with a michael@0: * window as the source. It would create a pixman image pointing michael@0: * to some bogus position in memory, but then set a clip region michael@0: * to the position where the actual bits were. michael@0: * michael@0: * Due to a bug in old versions of pixman, where it would not clip michael@0: * against the image bounds when a clip region was set, this would michael@0: * actually work. So when the pixman bug was fixed, a workaround was michael@0: * added to allow certain out-of-bound accesses. This function disabled michael@0: * those workarounds. michael@0: * michael@0: * Since 0.21.2, pixman doesn't do these workarounds anymore, so now michael@0: * this function is a no-op. michael@0: */ michael@0: PIXMAN_EXPORT void michael@0: pixman_disable_out_of_bounds_workaround (void) michael@0: { michael@0: } michael@0: michael@0: static void michael@0: compute_image_info (pixman_image_t *image) michael@0: { michael@0: pixman_format_code_t code; michael@0: uint32_t flags = 0; michael@0: michael@0: /* Transform */ michael@0: if (!image->common.transform) michael@0: { michael@0: flags |= (FAST_PATH_ID_TRANSFORM | michael@0: FAST_PATH_X_UNIT_POSITIVE | michael@0: FAST_PATH_Y_UNIT_ZERO | michael@0: FAST_PATH_AFFINE_TRANSFORM); michael@0: } michael@0: else michael@0: { michael@0: flags |= FAST_PATH_HAS_TRANSFORM; michael@0: michael@0: if (image->common.transform->matrix[2][0] == 0 && michael@0: image->common.transform->matrix[2][1] == 0 && michael@0: image->common.transform->matrix[2][2] == pixman_fixed_1) michael@0: { michael@0: flags |= FAST_PATH_AFFINE_TRANSFORM; michael@0: michael@0: if (image->common.transform->matrix[0][1] == 0 && michael@0: image->common.transform->matrix[1][0] == 0) michael@0: { michael@0: if (image->common.transform->matrix[0][0] == -pixman_fixed_1 && michael@0: image->common.transform->matrix[1][1] == -pixman_fixed_1) michael@0: { michael@0: flags |= FAST_PATH_ROTATE_180_TRANSFORM; michael@0: } michael@0: flags |= FAST_PATH_SCALE_TRANSFORM; michael@0: } michael@0: else if (image->common.transform->matrix[0][0] == 0 && michael@0: image->common.transform->matrix[1][1] == 0) michael@0: { michael@0: pixman_fixed_t m01 = image->common.transform->matrix[0][1]; michael@0: pixman_fixed_t m10 = image->common.transform->matrix[1][0]; michael@0: michael@0: if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1) michael@0: flags |= FAST_PATH_ROTATE_90_TRANSFORM; michael@0: else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1) michael@0: flags |= FAST_PATH_ROTATE_270_TRANSFORM; michael@0: } michael@0: } michael@0: michael@0: if (image->common.transform->matrix[0][0] > 0) michael@0: flags |= FAST_PATH_X_UNIT_POSITIVE; michael@0: michael@0: if (image->common.transform->matrix[1][0] == 0) michael@0: flags |= FAST_PATH_Y_UNIT_ZERO; michael@0: } michael@0: michael@0: /* Filter */ michael@0: switch (image->common.filter) michael@0: { michael@0: case PIXMAN_FILTER_NEAREST: michael@0: case PIXMAN_FILTER_FAST: michael@0: flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER); michael@0: break; michael@0: michael@0: case PIXMAN_FILTER_BILINEAR: michael@0: case PIXMAN_FILTER_GOOD: michael@0: case PIXMAN_FILTER_BEST: michael@0: flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER); michael@0: michael@0: /* Here we have a chance to optimize BILINEAR filter to NEAREST if michael@0: * they are equivalent for the currently used transformation matrix. michael@0: */ michael@0: if (flags & FAST_PATH_ID_TRANSFORM) michael@0: { michael@0: flags |= FAST_PATH_NEAREST_FILTER; michael@0: } michael@0: else if ( michael@0: /* affine and integer translation components in matrix ... */ michael@0: ((flags & FAST_PATH_AFFINE_TRANSFORM) && michael@0: !pixman_fixed_frac (image->common.transform->matrix[0][2] | michael@0: image->common.transform->matrix[1][2])) && michael@0: ( michael@0: /* ... combined with a simple rotation */ michael@0: (flags & (FAST_PATH_ROTATE_90_TRANSFORM | michael@0: FAST_PATH_ROTATE_180_TRANSFORM | michael@0: FAST_PATH_ROTATE_270_TRANSFORM)) || michael@0: /* ... or combined with a simple non-rotated translation */ michael@0: (image->common.transform->matrix[0][0] == pixman_fixed_1 && michael@0: image->common.transform->matrix[1][1] == pixman_fixed_1 && michael@0: image->common.transform->matrix[0][1] == 0 && michael@0: image->common.transform->matrix[1][0] == 0) michael@0: ) michael@0: ) michael@0: { michael@0: /* FIXME: there are some affine-test failures, showing that michael@0: * handling of BILINEAR and NEAREST filter is not quite michael@0: * equivalent when getting close to 32K for the translation michael@0: * components of the matrix. That's likely some bug, but for michael@0: * now just skip BILINEAR->NEAREST optimization in this case. michael@0: */ michael@0: pixman_fixed_t magic_limit = pixman_int_to_fixed (30000); michael@0: if (image->common.transform->matrix[0][2] <= magic_limit && michael@0: image->common.transform->matrix[1][2] <= magic_limit && michael@0: image->common.transform->matrix[0][2] >= -magic_limit && michael@0: image->common.transform->matrix[1][2] >= -magic_limit) michael@0: { michael@0: flags |= FAST_PATH_NEAREST_FILTER; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case PIXMAN_FILTER_CONVOLUTION: michael@0: break; michael@0: michael@0: case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: michael@0: flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER; michael@0: break; michael@0: michael@0: default: michael@0: flags |= FAST_PATH_NO_CONVOLUTION_FILTER; michael@0: break; michael@0: } michael@0: michael@0: /* Repeat mode */ michael@0: switch (image->common.repeat) michael@0: { michael@0: case PIXMAN_REPEAT_NONE: michael@0: flags |= michael@0: FAST_PATH_NO_REFLECT_REPEAT | michael@0: FAST_PATH_NO_PAD_REPEAT | michael@0: FAST_PATH_NO_NORMAL_REPEAT; michael@0: break; michael@0: michael@0: case PIXMAN_REPEAT_REFLECT: michael@0: flags |= michael@0: FAST_PATH_NO_PAD_REPEAT | michael@0: FAST_PATH_NO_NONE_REPEAT | michael@0: FAST_PATH_NO_NORMAL_REPEAT; michael@0: break; michael@0: michael@0: case PIXMAN_REPEAT_PAD: michael@0: flags |= michael@0: FAST_PATH_NO_REFLECT_REPEAT | michael@0: FAST_PATH_NO_NONE_REPEAT | michael@0: FAST_PATH_NO_NORMAL_REPEAT; michael@0: break; michael@0: michael@0: default: michael@0: flags |= michael@0: FAST_PATH_NO_REFLECT_REPEAT | michael@0: FAST_PATH_NO_PAD_REPEAT | michael@0: FAST_PATH_NO_NONE_REPEAT; michael@0: break; michael@0: } michael@0: michael@0: /* Component alpha */ michael@0: if (image->common.component_alpha) michael@0: flags |= FAST_PATH_COMPONENT_ALPHA; michael@0: else michael@0: flags |= FAST_PATH_UNIFIED_ALPHA; michael@0: michael@0: flags |= (FAST_PATH_NO_ACCESSORS | FAST_PATH_NARROW_FORMAT); michael@0: michael@0: /* Type specific checks */ michael@0: switch (image->type) michael@0: { michael@0: case SOLID: michael@0: code = PIXMAN_solid; michael@0: michael@0: if (image->solid.color.alpha == 0xffff) michael@0: flags |= FAST_PATH_IS_OPAQUE; michael@0: break; michael@0: michael@0: case BITS: michael@0: if (image->bits.width == 1 && michael@0: image->bits.height == 1 && michael@0: image->common.repeat != PIXMAN_REPEAT_NONE) michael@0: { michael@0: code = PIXMAN_solid; michael@0: } michael@0: else michael@0: { michael@0: code = image->bits.format; michael@0: flags |= FAST_PATH_BITS_IMAGE; michael@0: } michael@0: michael@0: if (!PIXMAN_FORMAT_A (image->bits.format) && michael@0: PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_GRAY && michael@0: PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_COLOR) michael@0: { michael@0: flags |= FAST_PATH_SAMPLES_OPAQUE; michael@0: michael@0: if (image->common.repeat != PIXMAN_REPEAT_NONE) michael@0: flags |= FAST_PATH_IS_OPAQUE; michael@0: } michael@0: michael@0: if (image->bits.read_func || image->bits.write_func) michael@0: flags &= ~FAST_PATH_NO_ACCESSORS; michael@0: michael@0: if (PIXMAN_FORMAT_IS_WIDE (image->bits.format)) michael@0: flags &= ~FAST_PATH_NARROW_FORMAT; michael@0: michael@0: if (image->bits.format == PIXMAN_r5g6b5) michael@0: flags |= FAST_PATH_16_FORMAT; michael@0: michael@0: break; michael@0: michael@0: case RADIAL: michael@0: code = PIXMAN_unknown; michael@0: michael@0: /* michael@0: * As explained in pixman-radial-gradient.c, every point of michael@0: * the plane has a valid associated radius (and thus will be michael@0: * colored) if and only if a is negative (i.e. one of the two michael@0: * circles contains the other one). michael@0: */ michael@0: michael@0: if (image->radial.a >= 0) michael@0: break; michael@0: michael@0: /* Fall through */ michael@0: michael@0: case CONICAL: michael@0: case LINEAR: michael@0: code = PIXMAN_unknown; michael@0: michael@0: if (image->common.repeat != PIXMAN_REPEAT_NONE) michael@0: { michael@0: int i; michael@0: michael@0: flags |= FAST_PATH_IS_OPAQUE; michael@0: for (i = 0; i < image->gradient.n_stops; ++i) michael@0: { michael@0: if (image->gradient.stops[i].color.alpha != 0xffff) michael@0: { michael@0: flags &= ~FAST_PATH_IS_OPAQUE; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: code = PIXMAN_unknown; michael@0: break; michael@0: } michael@0: michael@0: /* Alpha map */ michael@0: if (!image->common.alpha_map) michael@0: { michael@0: flags |= FAST_PATH_NO_ALPHA_MAP; michael@0: } michael@0: else michael@0: { michael@0: if (PIXMAN_FORMAT_IS_WIDE (image->common.alpha_map->format)) michael@0: flags &= ~FAST_PATH_NARROW_FORMAT; michael@0: } michael@0: michael@0: /* Both alpha maps and convolution filters can introduce michael@0: * non-opaqueness in otherwise opaque images. Also michael@0: * an image with component alpha turned on is only opaque michael@0: * if all channels are opaque, so we simply turn it off michael@0: * unconditionally for those images. michael@0: */ michael@0: if (image->common.alpha_map || michael@0: image->common.filter == PIXMAN_FILTER_CONVOLUTION || michael@0: image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION || michael@0: image->common.component_alpha) michael@0: { michael@0: flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE); michael@0: } michael@0: michael@0: image->common.flags = flags; michael@0: image->common.extended_format_code = code; michael@0: } michael@0: michael@0: void michael@0: _pixman_image_validate (pixman_image_t *image) michael@0: { michael@0: if (image->common.dirty) michael@0: { michael@0: compute_image_info (image); michael@0: michael@0: /* It is important that property_changed is michael@0: * called *after* compute_image_info() because michael@0: * property_changed() can make use of the flags michael@0: * to set up accessors etc. michael@0: */ michael@0: if (image->common.property_changed) michael@0: image->common.property_changed (image); michael@0: michael@0: image->common.dirty = FALSE; michael@0: } michael@0: michael@0: if (image->common.alpha_map) michael@0: _pixman_image_validate ((pixman_image_t *)image->common.alpha_map); michael@0: } michael@0: michael@0: PIXMAN_EXPORT pixman_bool_t michael@0: pixman_image_set_clip_region32 (pixman_image_t * image, michael@0: pixman_region32_t *region) michael@0: { michael@0: image_common_t *common = (image_common_t *)image; michael@0: pixman_bool_t result; michael@0: michael@0: if (region) michael@0: { michael@0: if ((result = pixman_region32_copy (&common->clip_region, region))) michael@0: image->common.have_clip_region = TRUE; michael@0: } michael@0: else michael@0: { michael@0: _pixman_image_reset_clip_region (image); michael@0: michael@0: result = TRUE; michael@0: } michael@0: michael@0: image_property_changed (image); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: PIXMAN_EXPORT pixman_bool_t michael@0: pixman_image_set_clip_region (pixman_image_t * image, michael@0: pixman_region16_t *region) michael@0: { michael@0: image_common_t *common = (image_common_t *)image; michael@0: pixman_bool_t result; michael@0: michael@0: if (region) michael@0: { michael@0: if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region))) michael@0: image->common.have_clip_region = TRUE; michael@0: } michael@0: else michael@0: { michael@0: _pixman_image_reset_clip_region (image); michael@0: michael@0: result = TRUE; michael@0: } michael@0: michael@0: image_property_changed (image); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_has_client_clip (pixman_image_t *image, michael@0: pixman_bool_t client_clip) michael@0: { michael@0: image->common.client_clip = client_clip; michael@0: } michael@0: michael@0: PIXMAN_EXPORT pixman_bool_t michael@0: pixman_image_set_transform (pixman_image_t * image, michael@0: const pixman_transform_t *transform) michael@0: { michael@0: static const pixman_transform_t id = michael@0: { michael@0: { { pixman_fixed_1, 0, 0 }, michael@0: { 0, pixman_fixed_1, 0 }, michael@0: { 0, 0, pixman_fixed_1 } } michael@0: }; michael@0: michael@0: image_common_t *common = (image_common_t *)image; michael@0: pixman_bool_t result; michael@0: michael@0: if (common->transform == transform) michael@0: return TRUE; michael@0: michael@0: if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0) michael@0: { michael@0: free (common->transform); michael@0: common->transform = NULL; michael@0: result = TRUE; michael@0: michael@0: goto out; michael@0: } michael@0: michael@0: if (common->transform && michael@0: memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0) michael@0: { michael@0: return TRUE; michael@0: } michael@0: michael@0: if (common->transform == NULL) michael@0: common->transform = malloc (sizeof (pixman_transform_t)); michael@0: michael@0: if (common->transform == NULL) michael@0: { michael@0: result = FALSE; michael@0: michael@0: goto out; michael@0: } michael@0: michael@0: memcpy (common->transform, transform, sizeof(pixman_transform_t)); michael@0: michael@0: result = TRUE; michael@0: michael@0: out: michael@0: image_property_changed (image); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_repeat (pixman_image_t *image, michael@0: pixman_repeat_t repeat) michael@0: { michael@0: if (image->common.repeat == repeat) michael@0: return; michael@0: michael@0: image->common.repeat = repeat; michael@0: michael@0: image_property_changed (image); michael@0: } michael@0: michael@0: PIXMAN_EXPORT pixman_bool_t michael@0: pixman_image_set_filter (pixman_image_t * image, michael@0: pixman_filter_t filter, michael@0: const pixman_fixed_t *params, michael@0: int n_params) michael@0: { michael@0: image_common_t *common = (image_common_t *)image; michael@0: pixman_fixed_t *new_params; michael@0: michael@0: if (params == common->filter_params && filter == common->filter) michael@0: return TRUE; michael@0: michael@0: if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION) michael@0: { michael@0: int width = pixman_fixed_to_int (params[0]); michael@0: int height = pixman_fixed_to_int (params[1]); michael@0: int x_phase_bits = pixman_fixed_to_int (params[2]); michael@0: int y_phase_bits = pixman_fixed_to_int (params[3]); michael@0: int n_x_phases = (1 << x_phase_bits); michael@0: int n_y_phases = (1 << y_phase_bits); michael@0: michael@0: return_val_if_fail ( michael@0: n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE); michael@0: } michael@0: michael@0: new_params = NULL; michael@0: if (params) michael@0: { michael@0: new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t)); michael@0: if (!new_params) michael@0: return FALSE; michael@0: michael@0: memcpy (new_params, michael@0: params, n_params * sizeof (pixman_fixed_t)); michael@0: } michael@0: michael@0: common->filter = filter; michael@0: michael@0: if (common->filter_params) michael@0: free (common->filter_params); michael@0: michael@0: common->filter_params = new_params; michael@0: common->n_filter_params = n_params; michael@0: michael@0: image_property_changed (image); michael@0: return TRUE; michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_source_clipping (pixman_image_t *image, michael@0: pixman_bool_t clip_sources) michael@0: { michael@0: if (image->common.clip_sources == clip_sources) michael@0: return; michael@0: michael@0: image->common.clip_sources = clip_sources; michael@0: michael@0: image_property_changed (image); michael@0: } michael@0: michael@0: /* Unlike all the other property setters, this function does not michael@0: * copy the content of indexed. Doing this copying is simply michael@0: * way, way too expensive. michael@0: */ michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_indexed (pixman_image_t * image, michael@0: const pixman_indexed_t *indexed) michael@0: { michael@0: bits_image_t *bits = (bits_image_t *)image; michael@0: michael@0: if (bits->indexed == indexed) michael@0: return; michael@0: michael@0: bits->indexed = indexed; michael@0: michael@0: image_property_changed (image); michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_alpha_map (pixman_image_t *image, michael@0: pixman_image_t *alpha_map, michael@0: int16_t x, michael@0: int16_t y) michael@0: { michael@0: image_common_t *common = (image_common_t *)image; michael@0: michael@0: return_if_fail (!alpha_map || alpha_map->type == BITS); michael@0: michael@0: if (alpha_map && common->alpha_count > 0) michael@0: { michael@0: /* If this image is being used as an alpha map itself, michael@0: * then you can't give it an alpha map of its own. michael@0: */ michael@0: return; michael@0: } michael@0: michael@0: if (alpha_map && alpha_map->common.alpha_map) michael@0: { michael@0: /* If the image has an alpha map of its own, michael@0: * then it can't be used as an alpha map itself michael@0: */ michael@0: return; michael@0: } michael@0: michael@0: if (common->alpha_map != (bits_image_t *)alpha_map) michael@0: { michael@0: if (common->alpha_map) michael@0: { michael@0: common->alpha_map->common.alpha_count--; michael@0: michael@0: pixman_image_unref ((pixman_image_t *)common->alpha_map); michael@0: } michael@0: michael@0: if (alpha_map) michael@0: { michael@0: common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map); michael@0: michael@0: common->alpha_map->common.alpha_count++; michael@0: } michael@0: else michael@0: { michael@0: common->alpha_map = NULL; michael@0: } michael@0: } michael@0: michael@0: common->alpha_origin_x = x; michael@0: common->alpha_origin_y = y; michael@0: michael@0: image_property_changed (image); michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_component_alpha (pixman_image_t *image, michael@0: pixman_bool_t component_alpha) michael@0: { michael@0: if (image->common.component_alpha == component_alpha) michael@0: return; michael@0: michael@0: image->common.component_alpha = component_alpha; michael@0: michael@0: image_property_changed (image); michael@0: } michael@0: michael@0: PIXMAN_EXPORT pixman_bool_t michael@0: pixman_image_get_component_alpha (pixman_image_t *image) michael@0: { michael@0: return image->common.component_alpha; michael@0: } michael@0: michael@0: PIXMAN_EXPORT void michael@0: pixman_image_set_accessors (pixman_image_t * image, michael@0: pixman_read_memory_func_t read_func, michael@0: pixman_write_memory_func_t write_func) michael@0: { michael@0: return_if_fail (image != NULL); michael@0: michael@0: if (image->type == BITS) michael@0: { michael@0: image->bits.read_func = read_func; michael@0: image->bits.write_func = write_func; michael@0: michael@0: image_property_changed (image); michael@0: } michael@0: } michael@0: michael@0: PIXMAN_EXPORT uint32_t * michael@0: pixman_image_get_data (pixman_image_t *image) michael@0: { michael@0: if (image->type == BITS) michael@0: return image->bits.bits; michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: PIXMAN_EXPORT int michael@0: pixman_image_get_width (pixman_image_t *image) michael@0: { michael@0: if (image->type == BITS) michael@0: return image->bits.width; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: PIXMAN_EXPORT int michael@0: pixman_image_get_height (pixman_image_t *image) michael@0: { michael@0: if (image->type == BITS) michael@0: return image->bits.height; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: PIXMAN_EXPORT int michael@0: pixman_image_get_stride (pixman_image_t *image) michael@0: { michael@0: if (image->type == BITS) michael@0: return image->bits.rowstride * (int) sizeof (uint32_t); michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: PIXMAN_EXPORT int michael@0: pixman_image_get_depth (pixman_image_t *image) michael@0: { michael@0: if (image->type == BITS) michael@0: return PIXMAN_FORMAT_DEPTH (image->bits.format); michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: PIXMAN_EXPORT pixman_format_code_t michael@0: pixman_image_get_format (pixman_image_t *image) michael@0: { michael@0: if (image->type == BITS) michael@0: return image->bits.format; michael@0: michael@0: return PIXMAN_null; michael@0: } michael@0: michael@0: uint32_t michael@0: _pixman_image_get_solid (pixman_implementation_t *imp, michael@0: pixman_image_t * image, michael@0: pixman_format_code_t format) michael@0: { michael@0: uint32_t result; michael@0: michael@0: if (image->type == SOLID) michael@0: { michael@0: result = image->solid.color_32; michael@0: } michael@0: else if (image->type == BITS) michael@0: { michael@0: if (image->bits.format == PIXMAN_a8r8g8b8) michael@0: result = image->bits.bits[0]; michael@0: else if (image->bits.format == PIXMAN_x8r8g8b8) michael@0: result = image->bits.bits[0] | 0xff000000; michael@0: else if (image->bits.format == PIXMAN_a8) michael@0: result = (*(uint8_t *)image->bits.bits) << 24; michael@0: else michael@0: goto otherwise; michael@0: } michael@0: else michael@0: { michael@0: pixman_iter_t iter; michael@0: michael@0: otherwise: michael@0: _pixman_implementation_src_iter_init ( michael@0: imp, &iter, image, 0, 0, 1, 1, michael@0: (uint8_t *)&result, michael@0: ITER_NARROW, image->common.flags); michael@0: michael@0: result = *iter.get_scanline (&iter, NULL); michael@0: } michael@0: michael@0: /* If necessary, convert RGB <--> BGR. */ michael@0: if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB michael@0: && PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB) michael@0: { michael@0: result = (((result & 0xff000000) >> 0) | michael@0: ((result & 0x00ff0000) >> 16) | michael@0: ((result & 0x0000ff00) >> 0) | michael@0: ((result & 0x000000ff) << 16)); michael@0: } michael@0: michael@0: return result; michael@0: }