pub mod backend;
pub mod color;
pub mod cosmic_text_renderer;
#[cfg(feature = "gpu")]
pub mod gpu;
#[cfg(feature = "parallel")]
pub mod parallel;
pub mod pooled;
pub mod primitives;
#[cfg(feature = "simd")]
pub mod simd;
pub mod skia;
pub mod style;
pub mod text;
pub(crate) mod text_anchor;
pub mod theme;
pub mod typst_text;
pub use backend::Renderer;
pub use color::{Color, ColorError, ColorMap};
pub use cosmic_text_renderer::CosmicTextRenderer;
#[cfg(feature = "gpu")]
pub use gpu::{GpuBackend, GpuRenderer, initialize_gpu_backend, is_gpu_available};
#[cfg(feature = "parallel")]
pub use parallel::{
DetailedPerformanceInfo, ParallelConfig, ParallelRenderer, PerformanceStats, SeriesRenderData,
};
pub use pooled::{LineSegment, PooledRenderer, PooledRendererStats, get_pooled_renderer};
pub use primitives::{Arc, Arrow, Polygon, Wedge};
#[cfg(feature = "simd")]
pub use simd::{CoordinateBounds, PixelViewport, SIMDPerformanceInfo, SIMDTransformer};
pub use skia::SkiaRenderer;
pub use style::{LineStyle, MarkerStyle};
pub use text::{FontConfig, FontFamily, FontStyle, FontWeight};
pub use text::{
TextRenderer, get_font_system, get_swash_cache, initialize_text_system, register_font_bytes,
};
pub use theme::{Theme, ThemeBuilder, ThemeVariant};
#[derive(Debug, Clone, Copy)]
pub struct Viewport {
pub x_range: (f64, f64),
pub y_range: (f64, f64),
pub margin: f64,
}
impl Viewport {
pub fn new(x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
Self {
x_range: (x_min, x_max),
y_range: (y_min, y_max),
margin: 0.0,
}
}
pub fn with_margin(mut self, margin: f64) -> Self {
self.margin = margin.max(0.0);
self
}
pub fn effective_x_range(&self) -> (f64, f64) {
let width = self.x_range.1 - self.x_range.0;
let margin_amount = width * self.margin;
(
self.x_range.0 - margin_amount,
self.x_range.1 + margin_amount,
)
}
pub fn effective_y_range(&self) -> (f64, f64) {
let height = self.y_range.1 - self.y_range.0;
let margin_amount = height * self.margin;
(
self.y_range.0 - margin_amount,
self.y_range.1 + margin_amount,
)
}
pub fn contains(&self, x: f64, y: f64) -> bool {
let (x_min, x_max) = self.effective_x_range();
let (y_min, y_max) = self.effective_y_range();
x >= x_min && x <= x_max && y >= y_min && y <= y_max
}
}
pub fn cull_to_viewport(points: &[(f64, f64)], viewport: &Viewport) -> Vec<(f64, f64)> {
points
.iter()
.copied()
.filter(|(x, y)| viewport.contains(*x, *y))
.collect()
}
pub fn cull_xy_to_viewport(
x_data: &[f64],
y_data: &[f64],
viewport: &Viewport,
) -> (Vec<f64>, Vec<f64>) {
let len = x_data.len().min(y_data.len());
let mut result_x = Vec::with_capacity(len);
let mut result_y = Vec::with_capacity(len);
for i in 0..len {
if viewport.contains(x_data[i], y_data[i]) {
result_x.push(x_data[i]);
result_y.push(y_data[i]);
}
}
(result_x, result_y)
}
#[cfg(test)]
mod viewport_tests {
use super::*;
#[test]
fn test_viewport_contains() {
let viewport = Viewport::new(0.0, 10.0, 0.0, 10.0);
assert!(viewport.contains(5.0, 5.0));
assert!(viewport.contains(0.0, 0.0));
assert!(viewport.contains(10.0, 10.0));
assert!(!viewport.contains(-1.0, 5.0));
assert!(!viewport.contains(11.0, 5.0));
assert!(!viewport.contains(5.0, -1.0));
assert!(!viewport.contains(5.0, 11.0));
}
#[test]
fn test_viewport_with_margin() {
let viewport = Viewport::new(0.0, 10.0, 0.0, 10.0).with_margin(0.1);
assert!(viewport.contains(-0.5, 5.0)); assert!(viewport.contains(10.5, 5.0)); assert!(!viewport.contains(-1.5, 5.0)); assert!(!viewport.contains(11.5, 5.0)); }
#[test]
fn test_cull_to_viewport() {
let points = vec![
(0.0, 0.0),
(5.0, 5.0),
(10.0, 10.0),
(15.0, 15.0),
(-5.0, 5.0),
];
let viewport = Viewport::new(0.0, 10.0, 0.0, 10.0);
let culled = cull_to_viewport(&points, &viewport);
assert_eq!(culled.len(), 3);
assert!(culled.contains(&(0.0, 0.0)));
assert!(culled.contains(&(5.0, 5.0)));
assert!(culled.contains(&(10.0, 10.0)));
assert!(!culled.contains(&(15.0, 15.0)));
assert!(!culled.contains(&(-5.0, 5.0)));
}
#[test]
fn test_cull_xy_to_viewport() {
let x = vec![0.0, 5.0, 10.0, 15.0, -5.0];
let y = vec![0.0, 5.0, 10.0, 15.0, 5.0];
let viewport = Viewport::new(0.0, 10.0, 0.0, 10.0);
let (culled_x, culled_y) = cull_xy_to_viewport(&x, &y, &viewport);
assert_eq!(culled_x.len(), 3);
assert_eq!(culled_y.len(), 3);
assert_eq!(culled_x[0], 0.0);
assert_eq!(culled_x[1], 5.0);
assert_eq!(culled_x[2], 10.0);
}
#[test]
fn test_culled_is_subset() {
let points: Vec<(f64, f64)> = (0..100).map(|i| (i as f64, (i * 2) as f64)).collect();
let viewport = Viewport::new(20.0, 40.0, 40.0, 80.0);
let culled = cull_to_viewport(&points, &viewport);
for point in &culled {
assert!(points.contains(point));
}
for (x, y) in &culled {
assert!(viewport.contains(*x, *y));
}
}
}