Skip to content

Commit

Permalink
Fix cursor formats
Browse files Browse the repository at this point in the history
While piet provides pixels in rgba order, the X11 server wants an u32 in
its native endianness with order argb. I even called a variable
argb32_format, but I still did not handle this difference.

This commit premultiplies the color component with the alpha, handles
the different component order and also converts to the server's
endianness.

Signed-off-by: Uli Schlachter <psychon@znc.in>
  • Loading branch information
psychon committed May 30, 2021
1 parent 8515c29 commit bb04bec
Showing 1 changed file with 19 additions and 7 deletions.
26 changes: 19 additions & 7 deletions druid-shell/src/platform/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use x11rb::protocol::render::{ConnectionExt as _, Pictformat};
use x11rb::protocol::xfixes::{ConnectionExt as _, Region as XRegion};
use x11rb::protocol::xproto::{
self, AtomEnum, ChangeWindowAttributesAux, ConfigureNotifyEvent, ConnectionExt, CreateGCAux,
EventMask, Gcontext, Pixmap, PropMode, Rectangle, Visualtype, WindowClass,
EventMask, Gcontext, ImageOrder as X11ImageOrder, Pixmap, PropMode, Rectangle, Visualtype, WindowClass,
};
use x11rb::wrapper::ConnectionExt as _;
use x11rb::xcb_ffi::XCBConnection;
Expand Down Expand Up @@ -1622,11 +1622,10 @@ impl WindowHandle {
None
}
Some(format) => {
// BEGIN: Lots of code just to get the image into a RENDER Picture

let conn = w.app.connection();
let screen = &conn.setup().roots[w.app.screen_num() as usize];
match make_cursor(&**conn, screen.root, format, desc) {
let setup = &conn.setup();
let screen = &setup.roots[w.app.screen_num() as usize];
match make_cursor(&**conn, setup.image_byte_order, screen.root, format, desc) {
// TODO: We 'leak' the cursor - nothing ever calls render_free_cursor
Ok(cursor) => Some(cursor),
Err(err) => {
Expand Down Expand Up @@ -1697,23 +1696,36 @@ unsafe impl HasRawWindowHandle for WindowHandle {

fn make_cursor(
conn: &XCBConnection,
byte_order: X11ImageOrder,
root_window: u32,
argb32_format: Pictformat,
desc: &CursorDesc,
) -> Result<Cursor, ReplyOrIdError> {
// BEGIN: Lots of code just to get the image into a RENDER Picture

fn multiply_alpha(color: u8, alpha: u8) -> u8 {
let (color, alpha) = (u16::from(color), u16::from(alpha));
let temp = color * alpha + 0x80u16;
((temp + (temp >> 8)) >> 8) as u8
}

// No idea how to sanely get the pixel values, so I'll go with 'insane':
// Iterate over all pixels and build an array
let pixels = desc
.image
.pixel_colors()
.flat_map(|row| {
row.flat_map(|color| {
// TODO: RENDER (likely) expects unpremultiplied alpha. We should convert.
let (r, g, b, a) = color.as_rgba8();
// RENDER wants premultiplied alpha
let (r, g, b) = (multiply_alpha(r, a), multiply_alpha(g, a), multiply_alpha(b, a));
// piet gives us rgba in this order, the server expects an u32 with argb.
let (b0, b1, b2, b3) = match byte_order {
X11ImageOrder::LSB_FIRST => (b, g, r, a),
_ => (a, r, g, b),
};
// TODO Ownership and flat_map don't go well together :-(
vec![r, g, b, a]
vec![b0, b1, b2, b3]
})
})
.collect::<Vec<u8>>();
Expand Down

0 comments on commit bb04bec

Please sign in to comment.