mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
buffer: add buffer_convert_cairo_surface_for_icon()
Which handles: - conversion from other pixel formats to ARGB32 - setting the logical size to the desired display size - downscaling very large images using CAIRO_FILTER_GOOD
This commit is contained in:
parent
22e50aa4e2
commit
2e9b5886ce
2 changed files with 65 additions and 0 deletions
|
|
@ -61,6 +61,18 @@ struct lab_data_buffer *buffer_adopt_cairo_surface(cairo_surface_t *surface);
|
||||||
struct lab_data_buffer *buffer_create_cairo(uint32_t logical_width,
|
struct lab_data_buffer *buffer_create_cairo(uint32_t logical_width,
|
||||||
uint32_t logical_height, float scale);
|
uint32_t logical_height, float scale);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a buffer from an image surface, for display as an icon.
|
||||||
|
*
|
||||||
|
* The surface is either adopted by the buffer (which takes ownership),
|
||||||
|
* or copied and then destroyed.
|
||||||
|
*
|
||||||
|
* This function allows non-ARGB32 source images and converts to
|
||||||
|
* CAIRO_FORMAT_ARGB32 if needed.
|
||||||
|
*/
|
||||||
|
struct lab_data_buffer *buffer_convert_cairo_surface_for_icon(
|
||||||
|
cairo_surface_t *surface, uint32_t icon_size, float scale);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a buffer which holds (and takes ownership of) raw pixel data
|
* Create a buffer which holds (and takes ownership of) raw pixel data
|
||||||
* in pre-multiplied ARGB32 format.
|
* in pre-multiplied ARGB32 format.
|
||||||
|
|
|
||||||
53
src/buffer.c
53
src/buffer.c
|
|
@ -29,6 +29,7 @@
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
#include <wlr/interfaces/wlr_buffer.h>
|
#include <wlr/interfaces/wlr_buffer.h>
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#include "common/box.h"
|
||||||
#include "common/mem.h"
|
#include "common/mem.h"
|
||||||
|
|
||||||
static const struct wlr_buffer_impl data_buffer_impl;
|
static const struct wlr_buffer_impl data_buffer_impl;
|
||||||
|
|
@ -134,6 +135,58 @@ buffer_create_cairo(uint32_t logical_width, uint32_t logical_height, float scale
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lab_data_buffer *
|
||||||
|
buffer_convert_cairo_surface_for_icon(cairo_surface_t *surface,
|
||||||
|
uint32_t icon_size, float scale)
|
||||||
|
{
|
||||||
|
assert(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute logical size for display and decide whether we can
|
||||||
|
* use the image data directly (fast path). Requirements are:
|
||||||
|
*
|
||||||
|
* - The pixel format must be ARGB32.
|
||||||
|
* - The image must not be so large as to need downsampling by
|
||||||
|
* more than 2x when displayed at the target scale. wlr_scene
|
||||||
|
* uses linear interpolation without pixel averaging, which
|
||||||
|
* starts to skip samples if downsampling more than 2x,
|
||||||
|
* resulting in a grainy look.
|
||||||
|
*/
|
||||||
|
int width = cairo_image_surface_get_width(surface);
|
||||||
|
int height = cairo_image_surface_get_height(surface);
|
||||||
|
struct wlr_box logical =
|
||||||
|
box_fit_within(width, height, icon_size, icon_size);
|
||||||
|
struct lab_data_buffer *buffer;
|
||||||
|
|
||||||
|
if (cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32
|
||||||
|
&& width <= 2 * logical.width * scale
|
||||||
|
&& height <= 2 * logical.height * scale) {
|
||||||
|
buffer = buffer_adopt_cairo_surface(surface);
|
||||||
|
/* set logical size for display */
|
||||||
|
buffer->logical_width = logical.width;
|
||||||
|
buffer->logical_height = logical.height;
|
||||||
|
} else {
|
||||||
|
/* convert to ARGB32 and scale for display (slow path) */
|
||||||
|
buffer = buffer_create_cairo(logical.width,
|
||||||
|
logical.height, scale);
|
||||||
|
|
||||||
|
cairo_t *cairo = buffer->cairo;
|
||||||
|
cairo_scale(cairo, (double)logical.width / width,
|
||||||
|
(double)logical.height / height);
|
||||||
|
cairo_set_source_surface(cairo, surface, 0, 0);
|
||||||
|
cairo_pattern_set_filter(cairo_get_source(cairo),
|
||||||
|
CAIRO_FILTER_GOOD);
|
||||||
|
cairo_paint(cairo);
|
||||||
|
|
||||||
|
/* ensure pixel data is updated */
|
||||||
|
cairo_surface_flush(buffer->surface);
|
||||||
|
/* destroy original surface */
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
struct lab_data_buffer *
|
struct lab_data_buffer *
|
||||||
buffer_create_from_data(void *pixel_data, uint32_t width, uint32_t height,
|
buffer_create_from_data(void *pixel_data, uint32_t width, uint32_t height,
|
||||||
uint32_t stride)
|
uint32_t stride)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue