2018-10-03 21:14:51 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
2018-09-29 22:36:53 +00:00
|
|
|
#pragma once
|
|
|
|
#include <pixman.h>
|
|
|
|
#include <stdio.h>
|
2019-03-27 15:33:55 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <xcb/xcb.h>
|
2018-12-20 02:49:29 +00:00
|
|
|
|
|
|
|
#include "log.h"
|
backend: gl: change how coordinates are modeled
So they closely match what the new backend interface wants.
The GL backends' coordinate system is so complicated, I don't think I
ever fully understood it. Hopefully it is clearer now. I made it so all
intermediate images used in the backend all have the same coordinate
system as the X server (i.e. (0, 0) at top-left, Y down, X to the
right), only at the final present step are the coordinates flipped. Thus
reduce the number of places where Y-flipping is done.
X pixmaps are usually Y-down as well, even if they are not, the backend
should handle them fine as well (though there's no way for me to
test that). (Cloned X pixmaps will have the same coordinates as X
pixmaps, so if X pixmaps aren't Y-down, there will also be some
complications there. But we will get rid of image cloning in the new
interface, so it's OK).
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 01:29:00 +00:00
|
|
|
#include "types.h"
|
2019-03-27 15:33:55 +00:00
|
|
|
#include "utils.h"
|
2018-10-21 01:56:50 +00:00
|
|
|
|
2018-09-29 22:36:53 +00:00
|
|
|
typedef struct pixman_region32 pixman_region32_t;
|
|
|
|
typedef struct pixman_box32 pixman_box32_t;
|
|
|
|
typedef pixman_region32_t region_t;
|
|
|
|
typedef pixman_box32_t rect_t;
|
|
|
|
|
|
|
|
RC_TYPE(region_t, rc_region, pixman_region32_init, pixman_region32_fini, static inline)
|
|
|
|
|
2019-03-27 15:33:55 +00:00
|
|
|
static inline void dump_region(const region_t *x) {
|
2024-04-14 17:24:40 +00:00
|
|
|
if (log_get_level_tls() > LOG_LEVEL_TRACE) {
|
2019-03-27 15:33:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
int nrects;
|
|
|
|
const rect_t *rects = pixman_region32_rectangles((region_t *)x, &nrects);
|
|
|
|
log_trace("nrects: %d", nrects);
|
2023-08-10 21:47:14 +00:00
|
|
|
for (int i = 0; i < nrects; i++) {
|
2019-03-27 15:33:55 +00:00
|
|
|
log_trace("(%d, %d) - (%d, %d)", rects[i].x1, rects[i].y1, rects[i].x2,
|
|
|
|
rects[i].y2);
|
2023-08-10 21:47:14 +00:00
|
|
|
}
|
2018-09-29 22:36:53 +00:00
|
|
|
}
|
2018-09-30 13:11:10 +00:00
|
|
|
|
2024-04-14 22:22:55 +00:00
|
|
|
static inline void log_region_(enum log_level level, const char *func, const region_t *x) {
|
|
|
|
if (level < log_get_level_tls()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nrects;
|
|
|
|
const rect_t *rects = pixman_region32_rectangles((region_t *)x, &nrects);
|
|
|
|
if (nrects == 0) {
|
|
|
|
log_printf(tls_logger, level, func, "\t(empty)");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < min2(nrects, 3); i++) {
|
|
|
|
log_printf(tls_logger, level, func, "\t(%d, %d) - (%d, %d)", rects[i].x1,
|
|
|
|
rects[i].y1, rects[i].x2, rects[i].y2);
|
|
|
|
}
|
|
|
|
if (nrects > 3) {
|
|
|
|
auto extent = pixman_region32_extents(x);
|
|
|
|
log_printf(tls_logger, level, func, "\t...");
|
|
|
|
log_printf(tls_logger, level, func, "\ttotal: (%d, %d) - (%d, %d)",
|
|
|
|
extent->x1, extent->y1, extent->x2, extent->y2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define log_region(level, x) log_region_(LOG_LEVEL_##level, __func__, x)
|
|
|
|
|
2018-09-30 13:11:10 +00:00
|
|
|
/// Convert one xcb rectangle to our rectangle type
|
2019-03-27 15:33:55 +00:00
|
|
|
static inline rect_t from_x_rect(const xcb_rectangle_t *rect) {
|
|
|
|
return (rect_t){
|
|
|
|
.x1 = rect->x,
|
|
|
|
.y1 = rect->y,
|
|
|
|
.x2 = rect->x + rect->width,
|
|
|
|
.y2 = rect->y + rect->height,
|
|
|
|
};
|
2018-09-30 13:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert an array of xcb rectangles to our rectangle type
|
|
|
|
/// Returning an array that needs to be freed
|
2019-03-27 15:33:55 +00:00
|
|
|
static inline rect_t *from_x_rects(int nrects, const xcb_rectangle_t *rects) {
|
|
|
|
rect_t *ret = ccalloc(nrects, rect_t);
|
2019-03-30 09:07:21 +00:00
|
|
|
for (int i = 0; i < nrects; i++) {
|
2019-03-27 15:33:55 +00:00
|
|
|
ret[i] = from_x_rect(rects + i);
|
2019-03-30 09:07:21 +00:00
|
|
|
}
|
2019-03-27 15:33:55 +00:00
|
|
|
return ret;
|
2018-09-30 13:11:10 +00:00
|
|
|
}
|
2019-07-06 12:26:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Resize a region.
|
|
|
|
*/
|
2023-08-10 21:47:14 +00:00
|
|
|
static inline void _resize_region(const region_t *region, region_t *output, int dx, int dy) {
|
2019-07-06 12:26:25 +00:00
|
|
|
if (!region || !output) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!dx && !dy) {
|
|
|
|
if (region != output) {
|
|
|
|
pixman_region32_copy(output, (region_t *)region);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Loop through all rectangles
|
|
|
|
int nrects;
|
|
|
|
int nnewrects = 0;
|
|
|
|
const rect_t *rects = pixman_region32_rectangles((region_t *)region, &nrects);
|
|
|
|
auto newrects = ccalloc(nrects, rect_t);
|
|
|
|
for (int i = 0; i < nrects; i++) {
|
|
|
|
int x1 = rects[i].x1 - dx;
|
|
|
|
int y1 = rects[i].y1 - dy;
|
|
|
|
int x2 = rects[i].x2 + dx;
|
|
|
|
int y2 = rects[i].y2 + dy;
|
|
|
|
int wid = x2 - x1;
|
|
|
|
int hei = y2 - y1;
|
|
|
|
if (wid <= 0 || hei <= 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-08-10 21:47:14 +00:00
|
|
|
newrects[nnewrects] = (rect_t){.x1 = x1, .x2 = x2, .y1 = y1, .y2 = y2};
|
2019-07-06 12:26:25 +00:00
|
|
|
++nnewrects;
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_fini(output);
|
|
|
|
pixman_region32_init_rects(output, newrects, nnewrects);
|
|
|
|
|
|
|
|
free(newrects);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline region_t resize_region(const region_t *region, int dx, int dy) {
|
|
|
|
region_t ret;
|
|
|
|
pixman_region32_init(&ret);
|
|
|
|
_resize_region(region, &ret, dx, dy);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void resize_region_in_place(region_t *region, int dx, int dy) {
|
|
|
|
return _resize_region(region, region, dx, dy);
|
|
|
|
}
|
backend: gl: change how coordinates are modeled
So they closely match what the new backend interface wants.
The GL backends' coordinate system is so complicated, I don't think I
ever fully understood it. Hopefully it is clearer now. I made it so all
intermediate images used in the backend all have the same coordinate
system as the X server (i.e. (0, 0) at top-left, Y down, X to the
right), only at the final present step are the coordinates flipped. Thus
reduce the number of places where Y-flipping is done.
X pixmaps are usually Y-down as well, even if they are not, the backend
should handle them fine as well (though there's no way for me to
test that). (Cloned X pixmaps will have the same coordinates as X
pixmaps, so if X pixmaps aren't Y-down, there will also be some
complications there. But we will get rid of image cloning in the new
interface, so it's OK).
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 01:29:00 +00:00
|
|
|
|
2024-05-11 01:06:49 +00:00
|
|
|
static inline rect_t region_translate_rect(rect_t rect, ivec2 origin) {
|
backend: gl: change how coordinates are modeled
So they closely match what the new backend interface wants.
The GL backends' coordinate system is so complicated, I don't think I
ever fully understood it. Hopefully it is clearer now. I made it so all
intermediate images used in the backend all have the same coordinate
system as the X server (i.e. (0, 0) at top-left, Y down, X to the
right), only at the final present step are the coordinates flipped. Thus
reduce the number of places where Y-flipping is done.
X pixmaps are usually Y-down as well, even if they are not, the backend
should handle them fine as well (though there's no way for me to
test that). (Cloned X pixmaps will have the same coordinates as X
pixmaps, so if X pixmaps aren't Y-down, there will also be some
complications there. But we will get rid of image cloning in the new
interface, so it's OK).
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 01:29:00 +00:00
|
|
|
return (rect_t){
|
|
|
|
.x1 = rect.x1 + origin.x,
|
|
|
|
.y1 = rect.y1 + origin.y,
|
|
|
|
.x2 = rect.x2 + origin.x,
|
|
|
|
.y2 = rect.y2 + origin.y,
|
|
|
|
};
|
2024-04-14 22:22:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Subtract `other`, placed at `origin`, from `region`.
|
2024-05-11 01:06:49 +00:00
|
|
|
static inline void region_subtract(region_t *region, ivec2 origin, const region_t *other) {
|
2024-04-14 22:22:55 +00:00
|
|
|
pixman_region32_translate(region, -origin.x, -origin.y);
|
|
|
|
pixman_region32_subtract(region, region, other);
|
|
|
|
pixman_region32_translate(region, origin.x, origin.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Union `region` with `other` placed at `origin`.
|
2024-05-11 01:06:49 +00:00
|
|
|
static inline void region_union(region_t *region, ivec2 origin, const region_t *other) {
|
2024-04-14 22:22:55 +00:00
|
|
|
pixman_region32_translate(region, -origin.x, -origin.y);
|
|
|
|
pixman_region32_union(region, region, other);
|
|
|
|
pixman_region32_translate(region, origin.x, origin.y);
|
|
|
|
}
|
2024-04-17 07:49:10 +00:00
|
|
|
|
|
|
|
/// Intersect `region` with `other` placed at `origin`.
|
2024-05-11 01:06:49 +00:00
|
|
|
static inline void region_intersect(region_t *region, ivec2 origin, const region_t *other) {
|
2024-04-17 07:49:10 +00:00
|
|
|
pixman_region32_translate(region, -origin.x, -origin.y);
|
|
|
|
pixman_region32_intersect(region, region, other);
|
|
|
|
pixman_region32_translate(region, origin.x, origin.y);
|
|
|
|
}
|
|
|
|
|
2024-05-15 01:54:01 +00:00
|
|
|
/// Calculate the symmetric difference of `region1`, and `region2`, and union the result
|
|
|
|
/// into `result`. The two input regions has to be in the same coordinate space.
|
2024-04-17 07:49:10 +00:00
|
|
|
///
|
|
|
|
/// @param scratch a region to store temporary results
|
2024-05-15 01:54:01 +00:00
|
|
|
static inline void
|
|
|
|
region_symmetric_difference_local(region_t *result, region_t *scratch,
|
|
|
|
const region_t *region1, const region_t *region2) {
|
2024-04-17 07:49:10 +00:00
|
|
|
pixman_region32_copy(scratch, region1);
|
2024-05-15 01:54:01 +00:00
|
|
|
pixman_region32_subtract(scratch, scratch, region2);
|
|
|
|
pixman_region32_union(result, result, scratch);
|
2024-04-17 07:49:10 +00:00
|
|
|
|
|
|
|
pixman_region32_copy(scratch, region2);
|
2024-05-15 01:54:01 +00:00
|
|
|
pixman_region32_subtract(scratch, scratch, region1);
|
|
|
|
pixman_region32_union(result, result, scratch);
|
2024-04-17 07:49:10 +00:00
|
|
|
}
|