summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Matsumura <gmmatsumura01@bvsd.org>2020-07-15 12:34:12 -0600
committerGeorge Matsumura <gmmatsumura01@bvsd.org>2020-08-25 02:30:58 -0600
commitb258f0203c4365a67e6cc88763608737badb4580 (patch)
treed532a0ab0c6e87b8b5976a837480ca9b856df546
parent20cc7ad16ea2fe95499813b93732b7d7bdefa4dc (diff)
downloadcairo-b258f0203c4365a67e6cc88763608737badb4580.tar.gz
cogl: Handle negative stride images correctly
This adds correct support for negative stride images by uploading them to a texture in their upside-down orientation and then vertically inverting the matrix with which they are read, which is required because OpenGL (and therefore cogl) cannot pack pixels with a negative stride. Signed-off-by: George Matsumura <gmmatsumura01@bvsd.org>
-rw-r--r--src/cairo-cogl-surface.c49
1 files changed, 44 insertions, 5 deletions
diff --git a/src/cairo-cogl-surface.c b/src/cairo-cogl-surface.c
index 9388189e2..8207532c4 100644
--- a/src/cairo-cogl-surface.c
+++ b/src/cairo-cogl-surface.c
@@ -1814,7 +1814,8 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surf
cairo_surface_t *surface,
const cairo_rectangle_int_t *extents,
const cairo_matrix_t *pattern_matrix,
- cairo_bool_t *has_pre_transform)
+ cairo_bool_t *has_pre_transform,
+ cairo_bool_t *vertical_invert)
{
cairo_image_surface_t *image;
cairo_image_surface_t *acquired_image = NULL;
@@ -1825,8 +1826,11 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surf
GError *error = NULL;
cairo_surface_t *clone;
cairo_matrix_t transform;
+ ptrdiff_t stride;
+ unsigned char *data;
*has_pre_transform = FALSE;
+ *vertical_invert = FALSE;
if (surface->device == reference_surface->base.device) {
_cairo_cogl_surface_flush ((cairo_cogl_surface_t *)surface, 0);
@@ -1923,12 +1927,26 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surf
assert (format);
}
+ if (image->stride < 0) {
+ /* If the stride is negative, this modifies the data pointer so
+ * that all of the pixels are read into the texture, but
+ * upside-down. We then set invert_vertical so that
+ * acquire_pattern_texture will adjust the texture sampling
+ * matrix to correct this. */
+ stride = image->stride * -1;
+ data = image->data - stride * (image->height - 1);
+ *vertical_invert = TRUE;
+ } else {
+ stride = image->stride;
+ data = image->data;
+ }
+
texture = cogl_texture_2d_new_from_data (to_device(reference_surface->base.device)->cogl_context,
image->width,
image->height,
format, /* incoming */
- image->stride,
- image->data,
+ stride,
+ data,
&error);
if (!texture) {
g_warning ("Failed to allocate texture: %s", error->message);
@@ -1987,6 +2005,7 @@ _cairo_cogl_acquire_pattern_texture (const cairo_pattern_t *pattern,
{
CoglTexture *texture = NULL;
cairo_bool_t has_pre_transform;
+ cairo_bool_t vertical_invert;
switch ((int)pattern->type)
{
@@ -1997,7 +2016,8 @@ _cairo_cogl_acquire_pattern_texture (const cairo_pattern_t *pattern,
surface,
extents,
&pattern->matrix,
- &has_pre_transform);
+ &has_pre_transform,
+ &vertical_invert);
if (!texture)
return NULL;
@@ -2030,6 +2050,15 @@ _cairo_cogl_acquire_pattern_texture (const cairo_pattern_t *pattern,
attributes->matrix.x0 *= xscale;
attributes->matrix.y0 *= yscale;
+ if (vertical_invert) {
+ /* Convert the normalized texture matrix so that we read
+ * the texture from the bottom up instead of from the top
+ * down */
+ attributes->matrix.yx *= -1.0;
+ attributes->matrix.yy *= -1.0;
+ attributes->matrix.y0 += 1.0;
+ }
+
attributes->extend = pattern->extend;
attributes->filter = CAIRO_FILTER_BILINEAR;
attributes->has_component_alpha = pattern->has_component_alpha;
@@ -2070,7 +2099,8 @@ _cairo_cogl_acquire_pattern_texture (const cairo_pattern_t *pattern,
surface,
NULL, // As long as the surface is an image,
NULL, // acquire_surface_texture shouldn't access these values
- &has_pre_transform);
+ &has_pre_transform,
+ &vertical_invert);
if (!texture)
goto BAIL;
@@ -2092,6 +2122,15 @@ _cairo_cogl_acquire_pattern_texture (const cairo_pattern_t *pattern,
attributes->matrix.x0 *= xscale;
attributes->matrix.y0 *= yscale;
+ if (vertical_invert) {
+ /* Convert the normalized texture matrix so that we read
+ * the texture from the bottom up instead of from the top
+ * down */
+ attributes->matrix.yx *= -1.0;
+ attributes->matrix.yy *= -1.0;
+ attributes->matrix.y0 += 1.0;
+ }
+
attributes->extend = pattern->extend;
attributes->filter = CAIRO_FILTER_NEAREST;
attributes->has_component_alpha = pattern->has_component_alpha;