1
0
Fork 0
forked from wry/wry

pango: move bindings into workspace crate

This commit is contained in:
kossLAN 2026-05-29 11:29:14 -04:00
parent ebaccd8762
commit 4562a34890
No known key found for this signature in database
8 changed files with 554 additions and 429 deletions

109
pango/src/consts.rs Normal file
View file

@ -0,0 +1,109 @@
#![allow(dead_code)]
cenum! {
CairoFormat, CAIRO_FORMATS;
CAIRO_FORMAT_INVALID = -1,
CAIRO_FORMAT_ARGB32 = 0,
CAIRO_FORMAT_RGB24 = 1,
CAIRO_FORMAT_A8 = 2,
CAIRO_FORMAT_A1 = 3,
CAIRO_FORMAT_RGB16_565 = 4,
CAIRO_FORMAT_RGB30 = 5,
CAIRO_FORMAT_RGB96F = 6,
CAIRO_FORMAT_RGBA128F = 7,
}
cenum! {
CairoStatus, CAIRO_STATUSES;
CAIRO_STATUS_SUCCESS = 0,
CAIRO_STATUS_NO_MEMORY = 1,
CAIRO_STATUS_INVALID_RESTORE = 2,
CAIRO_STATUS_INVALID_POP_GROUP = 3,
CAIRO_STATUS_NO_CURRENT_POINT = 4,
CAIRO_STATUS_INVALID_MATRIX = 5,
CAIRO_STATUS_INVALID_STATUS = 6,
CAIRO_STATUS_NULL_POINTER = 7,
CAIRO_STATUS_INVALID_STRING = 8,
CAIRO_STATUS_INVALID_PATH_DATA = 9,
CAIRO_STATUS_READ_ERROR = 10,
CAIRO_STATUS_WRITE_ERROR = 11,
CAIRO_STATUS_SURFACE_FINISHED = 12,
CAIRO_STATUS_SURFACE_TYPE_MISMATCH = 13,
CAIRO_STATUS_PATTERN_TYPE_MISMATCH = 14,
CAIRO_STATUS_INVALID_CONTENT = 15,
CAIRO_STATUS_INVALID_FORMAT = 16,
CAIRO_STATUS_INVALID_VISUAL = 17,
CAIRO_STATUS_FILE_NOT_FOUND = 18,
CAIRO_STATUS_INVALID_DASH = 19,
CAIRO_STATUS_INVALID_DSC_COMMENT = 20,
CAIRO_STATUS_INVALID_INDEX = 21,
CAIRO_STATUS_CLIP_NOT_REPRESENTABLE = 22,
CAIRO_STATUS_TEMP_FILE_ERROR = 23,
CAIRO_STATUS_INVALID_STRIDE = 24,
CAIRO_STATUS_FONT_TYPE_MISMATCH = 25,
CAIRO_STATUS_USER_FONT_IMMUTABLE = 26,
CAIRO_STATUS_USER_FONT_ERROR = 27,
CAIRO_STATUS_NEGATIVE_COUNT = 28,
CAIRO_STATUS_INVALID_CLUSTERS = 29,
CAIRO_STATUS_INVALID_SLANT = 30,
CAIRO_STATUS_INVALID_WEIGHT = 31,
CAIRO_STATUS_INVALID_SIZE = 32,
CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED = 33,
CAIRO_STATUS_DEVICE_TYPE_MISMATCH = 34,
CAIRO_STATUS_DEVICE_ERROR = 35,
CAIRO_STATUS_INVALID_MESH_CONSTRUCTION = 36,
CAIRO_STATUS_DEVICE_FINISHED = 37,
CAIRO_STATUS_JBIG2_GLOBAL_MISSING = 38,
CAIRO_STATUS_PNG_ERROR = 39,
CAIRO_STATUS_FREETYPE_ERROR = 40,
CAIRO_STATUS_WIN32_GDI_ERROR = 41,
CAIRO_STATUS_TAG_ERROR = 42,
CAIRO_STATUS_LAST_STATUS = 43,
}
cenum! {
CairoOperator, CAIRO_OPERATORS;
CAIRO_OPERATOR_CLEAR = 0,
CAIRO_OPERATOR_SOURCE = 1,
CAIRO_OPERATOR_OVER = 2,
CAIRO_OPERATOR_IN = 3,
CAIRO_OPERATOR_OUT = 4,
CAIRO_OPERATOR_ATOP = 5,
CAIRO_OPERATOR_DEST = 6,
CAIRO_OPERATOR_DEST_OVER = 7,
CAIRO_OPERATOR_DEST_IN = 8,
CAIRO_OPERATOR_DEST_OUT = 9,
CAIRO_OPERATOR_DEST_ATOP = 10,
CAIRO_OPERATOR_XOR = 11,
CAIRO_OPERATOR_ADD = 12,
CAIRO_OPERATOR_SATURATE = 13,
CAIRO_OPERATOR_MULTIPLY = 14,
CAIRO_OPERATOR_SCREEN = 15,
CAIRO_OPERATOR_OVERLAY = 16,
CAIRO_OPERATOR_DARKEN = 17,
CAIRO_OPERATOR_LIGHTEN = 18,
CAIRO_OPERATOR_COLOR_DODGE = 19,
CAIRO_OPERATOR_COLOR_BURN = 20,
CAIRO_OPERATOR_HARD_LIGHT = 21,
CAIRO_OPERATOR_SOFT_LIGHT = 22,
CAIRO_OPERATOR_DIFFERENCE = 23,
CAIRO_OPERATOR_EXCLUSION = 24,
CAIRO_OPERATOR_HSL_HUE = 25,
CAIRO_OPERATOR_HSL_SATURATION = 26,
CAIRO_OPERATOR_HSL_COLOR = 27,
CAIRO_OPERATOR_HSL_LUMINOSITY = 28,
}
cenum! {
PangoEllipsizeMode, PANGO_ELLIPSIZE_MODES;
PANGO_ELLIPSIZE_NONE = 0,
PANGO_ELLIPSIZE_START = 1,
PANGO_ELLIPSIZE_MIDDLE = 2,
PANGO_ELLIPSIZE_END = 3,
}
pub const PANGO_SCALE: i32 = 1024;

438
pango/src/lib.rs Normal file
View file

@ -0,0 +1,438 @@
#![allow(non_camel_case_types)]
use {
crate::consts::{CairoFormat, CairoOperator, PangoEllipsizeMode},
jay_geometry::Rect,
std::{cell::Cell, ptr, rc::Rc},
thiserror::Error,
uapi::{
IntoUstr,
c::{self, memset},
},
};
macro_rules! cenum {
($name:ident, $uc:ident; $($name2:ident = $val:expr,)*) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct $name(pub i32);
impl $name {
#[allow(dead_code)]
pub fn raw(self) -> i32 {
self.0
}
}
$(
pub const $name2: $name = $name($val);
)*
pub const $uc: &[i32] = &[$($val,)*];
};
}
pub mod consts;
include!(concat!(env!("OUT_DIR"), "/pango_tys.rs"));
#[repr(transparent)]
struct cairo_surface_t(u8);
#[repr(transparent)]
struct cairo_t(u8);
#[link(name = "cairo")]
unsafe extern "C" {
fn cairo_image_surface_create(
format: cairo_format_t,
width: c::c_int,
height: c::c_int,
) -> *mut cairo_surface_t;
fn cairo_image_surface_create_for_data(
data: *mut u8,
format: cairo_format_t,
width: c::c_int,
height: c::c_int,
stride: c::c_int,
) -> *mut cairo_surface_t;
fn cairo_image_surface_get_height(surface: *mut cairo_surface_t) -> c::c_int;
fn cairo_image_surface_get_stride(surface: *mut cairo_surface_t) -> c::c_int;
fn cairo_image_surface_get_data(surface: *mut cairo_surface_t) -> *mut u8;
fn cairo_surface_destroy(surface: *mut cairo_surface_t);
fn cairo_surface_status(surface: *mut cairo_surface_t) -> cairo_status_t;
fn cairo_surface_flush(surface: *mut cairo_surface_t);
fn cairo_create(surface: *mut cairo_surface_t) -> *mut cairo_t;
fn cairo_status(cairo: *mut cairo_t) -> cairo_status_t;
fn cairo_destroy(cairo: *mut cairo_t);
fn cairo_set_operator(cr: *mut cairo_t, op: cairo_operator_t);
fn cairo_set_source_rgba(cr: *mut cairo_t, red: f64, green: f64, blue: f64, alpha: f64);
fn cairo_move_to(cr: *mut cairo_t, x: f64, y: f64);
fn cairo_format_stride_for_width(format: cairo_format_t, width: c::c_int) -> c::c_int;
}
#[repr(transparent)]
struct PangoContext_(u8);
#[link(name = "pangocairo-1.0")]
unsafe extern "C" {
fn pango_cairo_create_context(cr: *mut cairo_t) -> *mut PangoContext_;
fn pango_cairo_show_layout(cr: *mut cairo_t, layout: *mut PangoLayout_);
}
#[repr(transparent)]
struct GObject(u8);
#[link(name = "gobject-2.0")]
unsafe extern "C" {
fn g_object_unref(object: *mut GObject);
}
#[repr(transparent)]
struct PangoFontDescription_(u8);
#[repr(transparent)]
struct PangoLayout_(u8);
#[link(name = "pango-1.0")]
unsafe extern "C" {
fn pango_font_description_from_string(str: *const c::c_char) -> *mut PangoFontDescription_;
fn pango_font_description_free(desc: *mut PangoFontDescription_);
fn pango_font_description_get_size(desc: *mut PangoFontDescription_) -> c::c_int;
fn pango_font_description_set_size(desc: *mut PangoFontDescription_, size: c::c_int);
fn pango_layout_new(context: *mut PangoContext_) -> *mut PangoLayout_;
fn pango_layout_set_width(layout: *mut PangoLayout_, width: c::c_int);
fn pango_layout_set_ellipsize(layout: *mut PangoLayout_, ellipsize: PangoEllipsizeMode_);
fn pango_layout_set_font_description(
layout: *mut PangoLayout_,
desc: *const PangoFontDescription_,
);
fn pango_layout_set_text(layout: *mut PangoLayout_, text: *const c::c_char, length: c::c_int);
fn pango_layout_set_markup(layout: *mut PangoLayout_, text: *const c::c_char, length: c::c_int);
fn pango_layout_get_pixel_size(
layout: *mut PangoLayout_,
width: *mut c::c_int,
height: *mut c::c_int,
);
fn pango_layout_get_extents(
layout: *mut PangoLayout_,
ink_rect: *mut PangoRectangle,
logical_rect: *mut PangoRectangle,
);
fn pango_layout_get_baseline(layout: *mut PangoLayout_) -> c::c_int;
fn pango_extents_to_pixels(inclusive: *mut PangoRectangle, nearest: *mut PangoRectangle);
}
#[derive(Debug, Error)]
pub enum PangoError {
#[error("Could not create an image surface: {0}")]
CreateSurface(u32),
#[error("Could not create a cairo context: {0}")]
CreateCairo(u32),
#[error("Could not create a pangocairo context")]
CreatePangoCairo,
#[error("Could not create a pango layout")]
CreateLayout,
#[error("Could not retrieve image data")]
GetData,
}
#[repr(C)]
#[derive(Default)]
struct PangoRectangle {
x: c::c_int,
y: c::c_int,
width: c::c_int,
height: c::c_int,
}
const PANGO_SCALE: i32 = 1024;
pub struct CairoImageSurface {
s: *mut cairo_surface_t,
}
impl CairoImageSurface {
pub fn new_image_surface(
format: CairoFormat,
width: i32,
height: i32,
) -> Result<Rc<Self>, PangoError> {
unsafe {
let s = cairo_image_surface_create(format.raw() as _, width as _, height as _);
let status = cairo_surface_status(s);
if status != 0 {
return Err(PangoError::CreateSurface(status as _));
}
Ok(Rc::new(Self { s }))
}
}
pub unsafe fn new_image_surface_with_data(
format: CairoFormat,
data: *mut u8,
width: i32,
height: i32,
stride: i32,
) -> Result<Rc<Self>, PangoError> {
unsafe {
memset(data.cast(), 0, (stride * height) as usize);
let s = cairo_image_surface_create_for_data(
data,
format.raw() as _,
width as _,
height as _,
stride as _,
);
let status = cairo_surface_status(s);
if status != 0 {
return Err(PangoError::CreateSurface(status as _));
}
Ok(Rc::new(Self { s }))
}
}
pub fn create_context(self: &Rc<Self>) -> Result<Rc<CairoContext>, PangoError> {
unsafe {
let c = cairo_create(self.s);
let status = cairo_status(c);
if status != 0 {
return Err(PangoError::CreateCairo(status as _));
}
Ok(Rc::new(CairoContext {
_s: self.clone(),
c,
}))
}
}
pub fn flush(&self) {
unsafe {
cairo_surface_flush(self.s);
}
}
pub fn height(&self) -> i32 {
unsafe { cairo_image_surface_get_height(self.s) as _ }
}
pub fn stride(&self) -> i32 {
unsafe { cairo_image_surface_get_stride(self.s) as _ }
}
pub fn data(&self) -> Result<&[Cell<u8>], PangoError> {
unsafe {
let d = cairo_image_surface_get_data(self.s);
if d.is_null() {
return Err(PangoError::GetData);
}
let size = self.height() as usize * self.stride() as usize;
Ok(std::slice::from_raw_parts(d.cast(), size))
}
}
}
impl Drop for CairoImageSurface {
fn drop(&mut self) {
unsafe {
cairo_surface_destroy(self.s);
}
}
}
pub struct CairoContext {
_s: Rc<CairoImageSurface>,
c: *mut cairo_t,
}
impl CairoContext {
pub fn create_pango_context(self: &Rc<Self>) -> Result<Rc<PangoCairoContext>, PangoError> {
unsafe {
let p = pango_cairo_create_context(self.c);
if p.is_null() {
return Err(PangoError::CreatePangoCairo);
}
Ok(Rc::new(PangoCairoContext { c: self.clone(), p }))
}
}
pub fn set_operator(&self, op: CairoOperator) {
unsafe {
cairo_set_operator(self.c, op.raw() as _);
}
}
pub fn set_source_rgba(&self, r: f64, g: f64, b: f64, a: f64) {
unsafe {
cairo_set_source_rgba(self.c, r, g, b, a);
}
}
pub fn move_to(&self, x: f64, y: f64) {
unsafe {
cairo_move_to(self.c, x, y);
}
}
}
impl Drop for CairoContext {
fn drop(&mut self) {
unsafe {
cairo_destroy(self.c);
}
}
}
pub struct PangoCairoContext {
c: Rc<CairoContext>,
p: *mut PangoContext_,
}
impl PangoCairoContext {
pub fn create_layout(self: &Rc<Self>) -> Result<PangoLayout, PangoError> {
unsafe {
let l = pango_layout_new(self.p as _);
if l.is_null() {
return Err(PangoError::CreateLayout);
}
Ok(PangoLayout { c: self.clone(), l })
}
}
}
impl Drop for PangoCairoContext {
fn drop(&mut self) {
unsafe {
g_object_unref(self.p as _);
}
}
}
pub struct PangoFontDescription {
s: *mut PangoFontDescription_,
}
impl PangoFontDescription {
pub fn from_string<'a>(s: impl IntoUstr<'a>) -> Self {
let s = s.into_ustr();
Self {
s: unsafe { pango_font_description_from_string(s.as_ptr()) },
}
}
pub fn size(&self) -> i32 {
unsafe { pango_font_description_get_size(self.s) as _ }
}
pub fn set_size(&mut self, size: i32) {
unsafe {
pango_font_description_set_size(self.s, size);
}
}
}
impl Drop for PangoFontDescription {
fn drop(&mut self) {
unsafe {
pango_font_description_free(self.s);
}
}
}
pub struct PangoLayout {
c: Rc<PangoCairoContext>,
l: *mut PangoLayout_,
}
impl PangoLayout {
pub fn set_width(&self, width: i32) {
unsafe {
pango_layout_set_width(self.l, width as _);
}
}
pub fn set_ellipsize(&self, ellipsize: PangoEllipsizeMode) {
unsafe {
pango_layout_set_ellipsize(self.l, ellipsize.raw() as _);
}
}
pub fn set_font_description(&self, fd: &PangoFontDescription) {
unsafe {
pango_layout_set_font_description(self.l, fd.s);
}
}
pub fn set_text(&self, text: &str) {
unsafe {
pango_layout_set_text(self.l, text.as_ptr() as _, text.len() as _);
}
}
pub fn set_markup(&self, text: &str) {
unsafe {
pango_layout_set_markup(self.l, text.as_ptr() as _, text.len() as _);
}
}
pub fn pixel_size(&self) -> (i32, i32) {
unsafe {
let mut w = 0;
let mut h = 0;
pango_layout_get_pixel_size(self.l, &mut w, &mut h);
(w as _, h as _)
}
}
pub fn inc_pixel_rect(&self) -> Rect {
unsafe {
let mut rect = PangoRectangle::default();
pango_layout_get_extents(self.l, &mut rect, ptr::null_mut());
pango_extents_to_pixels(&mut rect, ptr::null_mut());
Rect::new_sized_saturating(rect.x, rect.y, rect.width, rect.height)
}
}
pub fn logical_pixel_rect(&self) -> Rect {
unsafe {
let mut rect = PangoRectangle::default();
pango_layout_get_extents(self.l, ptr::null_mut(), &mut rect);
pango_extents_to_pixels(&mut rect, ptr::null_mut());
Rect::new_sized_saturating(rect.x, rect.y, rect.width, rect.height)
}
}
pub fn pixel_baseline(&self) -> i32 {
unsafe {
let res = pango_layout_get_baseline(self.l);
(res as i32 + PANGO_SCALE - 1) / PANGO_SCALE
}
}
pub fn show_layout(&self) {
unsafe {
pango_cairo_show_layout(self.c.c.c, self.l);
}
}
}
impl Drop for PangoLayout {
fn drop(&mut self) {
unsafe {
g_object_unref(self.l as _);
}
}
}
pub fn cairo_size(format: CairoFormat, width: i32, height: i32) -> Option<(i32, usize)> {
let stride = unsafe { cairo_format_stride_for_width(format.raw() as _, width as _) };
if stride < 0 {
return None;
}
let stride = stride as i32;
let size = height.checked_mul(stride)? as usize;
Some((stride, size))
}