From: Ben Pfaff Date: Sat, 19 Apr 2025 19:29:04 +0000 (-0700) Subject: work on cairo driver X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54c58942dac99f5fd183a959521cc0731a21ad65;p=pspp work on cairo driver --- diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 1a6e0fa4c4..625ffceed7 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -210,6 +210,29 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "cairo-rs" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae50b5510d86cf96ac2370e66d8dc960882f3df179d6a5a1e52bd94a1416c0f7" +dependencies = [ + "bitflags 2.6.0", + "cairo-sys-rs", + "glib", + "libc", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18b6bb8e43c7eb0f2aac7976afe0c61b6f5fc2ab7bc4c139537ea56c92290df" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "cc" version = "1.1.13" @@ -219,6 +242,16 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-expr" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -522,6 +555,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -587,6 +631,91 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "gio" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f00c70f8029d84ea7572dd0e1aaa79e5329667b4c17f329d79ffb1e6277487" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "pin-project-lite", + "smallvec", +] + +[[package]] +name = "gio-sys" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "160eb5250a26998c3e1b54e6a3d4ea15c6c7762a6062a19a7b63eff6e2b33f9e" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "windows-sys 0.52.0", +] + +[[package]] +name = "glib" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707b819af8059ee5395a2de9f2317d87a53dbad8846a2f089f0bb44703f37686" +dependencies = [ + "bitflags 2.6.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "smallvec", +] + +[[package]] +name = "glib-macros" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "glib-sys" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8928869a44cfdd1fccb17d6746e4ff82c8f82e41ce705aa026a52ca8dc3aefb" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c773a3cb38a419ad9c26c81d177d96b4b08980e8bdbbf32dace883e96e96e7e3" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -928,6 +1057,56 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "pango" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1f5dc1b8cf9bc08bfc0843a04ee0fa2e78f1e1fa4b126844a383af4f25f0ec" +dependencies = [ + "gio", + "glib", + "libc", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dbb9b751673bd8fe49eb78620547973a1e719ed431372122b20abd12445bab5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "pangocairo" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4690509a2fea2a6552a0ef8aa3e5f790c1365365ee0712afa1aedb39af3997b6" +dependencies = [ + "cairo-rs", + "glib", + "libc", + "pango", + "pangocairo-sys", +] + +[[package]] +name = "pangocairo-sys" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be6ac24147911a6a46783922fc288cf02f67570bc0d360e563b5b26aead6767" +dependencies = [ + "cairo-sys-rs", + "glib-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -989,6 +1168,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "portable-atomic" version = "1.11.0" @@ -1013,6 +1198,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -1029,6 +1223,7 @@ dependencies = [ "anyhow", "binrw", "bitflags 2.6.0", + "cairo-rs", "chardetng", "chrono", "clap", @@ -1054,6 +1249,8 @@ dependencies = [ "num-derive", "num-traits", "ordered-float", + "pango", + "pangocairo", "pspp-derive", "quick-xml", "rand", @@ -1261,6 +1458,15 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1338,6 +1544,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "termcolor" version = "0.3.6" @@ -1434,6 +1659,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -1597,6 +1856,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" @@ -1858,6 +2123,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" diff --git a/rust/pspp/Cargo.toml b/rust/pspp/Cargo.toml index 07f6d4ebf3..3dc3a805cd 100644 --- a/rust/pspp/Cargo.toml +++ b/rust/pspp/Cargo.toml @@ -42,6 +42,9 @@ color = { version = "0.2.3", features = ["serde"] } binrw = "0.14.1" ndarray = "0.16.1" derive_more = { version = "2.0.1", features = ["debug"] } +cairo-rs = { version = "0.20.7", features = ["ps", "png", "pdf", "svg"] } +pango = "0.20.9" +pangocairo = "0.20.7" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.48.0", features = ["Win32_Globalization"] } diff --git a/rust/pspp/src/output/cairo.rs b/rust/pspp/src/output/cairo.rs new file mode 100644 index 0000000000..b6cdeb922f --- /dev/null +++ b/rust/pspp/src/output/cairo.rs @@ -0,0 +1,743 @@ +use std::{ + borrow::Cow, cmp::min, f64::consts::PI, fmt::Write, ops::DerefMut, path::Path, sync::Arc, +}; + +use cairo::{Context, PdfSurface, Surface}; +use enum_map::{enum_map, EnumMap}; +use itertools::Itertools; +use pango::{ + parse_markup, AttrFloat, AttrFontDesc, AttrInt, AttrList, Attribute, FontDescription, FontMask, + Layout, Underline, Weight, SCALE, SCALE_SMALL, +}; +use pangocairo::functions::show_layout; +use smallvec::{smallvec, SmallVec}; + +use crate::output::{ + driver::Driver, + page::Setup, + pivot::{Color, Coord2, FontStyle, HorzAlign, Stroke}, + render::{Device, DrawCell, Extreme, Params}, + table::Content, + Item, +}; + +use super::pivot::{Axis2, BorderStyle, Rect2}; + +/// Width of an ordinary line. +const LINE_WIDTH: usize = LINE_SPACE / 2; + +/// Space between double lines. +const LINE_SPACE: usize = SCALE as usize; + +/// Conversion from 1/96" units ("pixels") to Cairo/Pango units. +fn px_to_xr(x: usize) -> usize { + x * 3 * (SCALE as usize * 72 / 96) / 3 +} + +fn xr_to_pt(x: usize) -> f64 { + x as f64 / SCALE as f64 +} + +fn xr_to_pango(x: usize) -> usize { + x +} + +/// Conversion from 1/96" units ("pixels") to Cairo/Pango units. +fn pxf_to_xr(x: f64) -> usize { + (x * (SCALE as f64 * 72.0 / 96.0)).round() as usize +} + +pub struct Style { + /// Page size. + pub size: Coord2, + + /// Minimum cell size to allow breaking. + pub min_break: EnumMap, + + /// The basic font. + pub font: FontDescription, + + /// Foreground color. + pub fg: Color, + + /// Use system colors? + pub use_system_colors: bool, + + /// Vertical space between different output items. + pub object_spacing: usize, + + /// Resolution, in units per inch, used for measuring font "points": + /// + /// - 72.0 if 1 pt is one device unit, e.g. for rendering to a surface + /// created by [PsSurface::new] with its default transformation matrix of 72 + /// units/inch.p + /// + /// - 96.0 is traditional for a screen-based surface. + pub font_resolution: f64, +} + +impl Style { + fn new_layout(&self, context: &Context) -> Layout { + let pangocairo_context = pangocairo::functions::create_context(context); + pangocairo::functions::context_set_resolution(&pangocairo_context, self.font_resolution); + Layout::new(&pangocairo_context) + } +} + +pub struct CairoRenderer { + style: Arc