pango: move bindings into workspace crate
This commit is contained in:
parent
ebaccd8762
commit
4562a34890
8 changed files with 554 additions and 429 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -713,6 +713,7 @@ dependencies = [
|
||||||
"jay-io-uring",
|
"jay-io-uring",
|
||||||
"jay-layout-animation",
|
"jay-layout-animation",
|
||||||
"jay-logger",
|
"jay-logger",
|
||||||
|
"jay-pango",
|
||||||
"jay-pr-caps",
|
"jay-pr-caps",
|
||||||
"jay-sighand",
|
"jay-sighand",
|
||||||
"jay-time",
|
"jay-time",
|
||||||
|
|
@ -886,6 +887,17 @@ dependencies = [
|
||||||
"uapi",
|
"uapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jay-pango"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"jay-geometry",
|
||||||
|
"repc",
|
||||||
|
"thiserror",
|
||||||
|
"uapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jay-pr-caps"
|
name = "jay-pr-caps"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ members = [
|
||||||
"bugs",
|
"bugs",
|
||||||
"logger",
|
"logger",
|
||||||
"video-types",
|
"video-types",
|
||||||
|
"pango",
|
||||||
"toml-config",
|
"toml-config",
|
||||||
"algorithms",
|
"algorithms",
|
||||||
"toml-spec",
|
"toml-spec",
|
||||||
|
|
@ -87,6 +88,7 @@ jay-pr-caps = { version = "0.1.0", path = "pr-caps" }
|
||||||
jay-bugs = { version = "0.1.0", path = "bugs" }
|
jay-bugs = { version = "0.1.0", path = "bugs" }
|
||||||
jay-logger = { version = "0.1.0", path = "logger" }
|
jay-logger = { version = "0.1.0", path = "logger" }
|
||||||
jay-video-types = { version = "0.1.0", path = "video-types" }
|
jay-video-types = { version = "0.1.0", path = "video-types" }
|
||||||
|
jay-pango = { version = "0.1.0", path = "pango" }
|
||||||
|
|
||||||
uapi = "0.2.13"
|
uapi = "0.2.13"
|
||||||
thiserror = "2.0.11"
|
thiserror = "2.0.11"
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,6 @@ mod macros;
|
||||||
#[path = "../src/libinput/consts.rs"]
|
#[path = "../src/libinput/consts.rs"]
|
||||||
mod libinput;
|
mod libinput;
|
||||||
|
|
||||||
#[path = "../src/pango/consts.rs"]
|
|
||||||
mod pango;
|
|
||||||
|
|
||||||
#[path = "../src/fontconfig/consts.rs"]
|
#[path = "../src/fontconfig/consts.rs"]
|
||||||
mod fontconfig;
|
mod fontconfig;
|
||||||
|
|
||||||
|
|
@ -145,12 +142,6 @@ pub fn main() -> anyhow::Result<()> {
|
||||||
"libinput_config_middle_emulation_state",
|
"libinput_config_middle_emulation_state",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut f = open("pango_tys.rs")?;
|
|
||||||
write_ty(&mut f, pango::CAIRO_FORMATS, "cairo_format_t")?;
|
|
||||||
write_ty(&mut f, pango::CAIRO_STATUSES, "cairo_status_t")?;
|
|
||||||
write_ty(&mut f, pango::CAIRO_OPERATORS, "cairo_operator_t")?;
|
|
||||||
write_ty(&mut f, pango::PANGO_ELLIPSIZE_MODES, "PangoEllipsizeMode_")?;
|
|
||||||
|
|
||||||
let mut f = open("fontconfig_tys.rs")?;
|
let mut f = open("fontconfig_tys.rs")?;
|
||||||
write_ty(&mut f, fontconfig::FC_MATCH_KINDS, "FcMatchKind")?;
|
write_ty(&mut f, fontconfig::FC_MATCH_KINDS, "FcMatchKind")?;
|
||||||
write_ty(&mut f, fontconfig::FC_RESULTS, "FcResult")?;
|
write_ty(&mut f, fontconfig::FC_RESULTS, "FcResult")?;
|
||||||
|
|
|
||||||
16
pango/Cargo.toml
Normal file
16
pango/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "jay-pango"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
jay-geometry = { version = "0.1.0", path = "../geometry" }
|
||||||
|
|
||||||
|
thiserror = "2.0.11"
|
||||||
|
uapi = "0.2.13"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
anyhow = "1.0.79"
|
||||||
|
repc = "0.1.1"
|
||||||
85
pango/build.rs
Normal file
85
pango/build.rs
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
use {
|
||||||
|
repc::layout::{Type, TypeVariant},
|
||||||
|
std::{
|
||||||
|
env,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io::{self, BufWriter, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! cenum {
|
||||||
|
($name:ident, $uc:ident; $($name2:ident = $val:expr,)*) => {
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct $name(pub i32);
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
pub fn raw(self) -> i32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
pub const $name2: $name = $name($val);
|
||||||
|
)*
|
||||||
|
|
||||||
|
pub const $uc: &[i32] = &[$($val,)*];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[path = "src/consts.rs"]
|
||||||
|
mod consts;
|
||||||
|
|
||||||
|
fn open(s: &str) -> io::Result<BufWriter<File>> {
|
||||||
|
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
path.push(s);
|
||||||
|
Ok(BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(path)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_target() -> repc::Target {
|
||||||
|
let rustc_target = env::var("TARGET").unwrap();
|
||||||
|
repc::TARGET_MAP
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.find(|t| t.0 == rustc_target)
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_enum_ty(variants: Vec<i128>) -> anyhow::Result<u64> {
|
||||||
|
let target = get_target();
|
||||||
|
let ty = Type {
|
||||||
|
layout: (),
|
||||||
|
annotations: vec![],
|
||||||
|
variant: TypeVariant::Enum(variants),
|
||||||
|
};
|
||||||
|
let ty = repc::compute_layout(target, &ty)?;
|
||||||
|
assert!(ty.layout.pointer_alignment_bits <= ty.layout.size_bits);
|
||||||
|
Ok(ty.layout.size_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_ty<W: Write>(f: &mut W, vals: &[i32], ty: &str) -> anyhow::Result<()> {
|
||||||
|
let variants: Vec<_> = vals.iter().cloned().map(|v| v as i128).collect();
|
||||||
|
let size = get_enum_ty(variants)?;
|
||||||
|
writeln!(f, "#[allow(clippy::allow_attributes, dead_code)]")?;
|
||||||
|
writeln!(f, "pub type {} = i{};", ty, size)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let mut f = open("pango_tys.rs")?;
|
||||||
|
write_ty(&mut f, consts::CAIRO_FORMATS, "cairo_format_t")?;
|
||||||
|
write_ty(&mut f, consts::CAIRO_STATUSES, "cairo_status_t")?;
|
||||||
|
write_ty(&mut f, consts::CAIRO_OPERATORS, "cairo_operator_t")?;
|
||||||
|
write_ty(&mut f, consts::PANGO_ELLIPSIZE_MODES, "PangoEllipsizeMode_")?;
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=src/consts.rs");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
438
pango/src/lib.rs
Normal file
438
pango/src/lib.rs
Normal 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))
|
||||||
|
}
|
||||||
421
src/pango.rs
421
src/pango.rs
|
|
@ -1,420 +1 @@
|
||||||
#![allow(non_camel_case_types)]
|
pub use jay_pango::*;
|
||||||
|
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
pango::consts::{CairoFormat, CairoOperator, PangoEllipsizeMode},
|
|
||||||
rect::Rect,
|
|
||||||
},
|
|
||||||
std::{cell::Cell, ptr, rc::Rc},
|
|
||||||
thiserror::Error,
|
|
||||||
uapi::{
|
|
||||||
IntoUstr,
|
|
||||||
c::{self, memset},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue