use std::fs;
use std::path::PathBuf;
use std::sync::Arc;
use typf_core::{
traits::{FontRef, Renderer},
types::{BitmapFormat, Direction, PositionedGlyph, RenderOutput, ShapingResult},
RenderParams,
};
use typf_render_opixa::OpixaRenderer;
struct TestFont {
data: Vec<u8>,
upem: u16,
}
impl FontRef for TestFont {
fn data(&self) -> &[u8] {
&self.data
}
fn units_per_em(&self) -> u16 {
self.upem
}
fn glyph_id(&self, _ch: char) -> Option<u32> {
Some(0) }
fn advance_width(&self, _glyph_id: u32) -> f32 {
500.0
}
fn glyph_count(&self) -> Option<u32> {
Some(100)
}
}
fn test_font_path(name: &str) -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.pop(); path.pop(); path.push("test-fonts");
path.push(name);
path
}
fn load_font(name: &str) -> Option<Arc<dyn FontRef>> {
let path = test_font_path(name);
if !path.exists() {
return None;
}
let data = fs::read(&path).ok()?;
Some(Arc::new(TestFont { data, upem: 1000 }) as Arc<dyn FontRef>)
}
fn simple_shaping_result() -> ShapingResult {
let glyphs = vec![
PositionedGlyph {
id: 36, x: 0.0,
y: 0.0,
advance: 100.0,
cluster: 0,
},
PositionedGlyph {
id: 72, x: 100.0,
y: 0.0,
advance: 80.0,
cluster: 1,
},
];
ShapingResult {
glyphs,
advance_width: 180.0,
advance_height: 200.0,
direction: Direction::LeftToRight,
}
}
#[test]
fn test_opixa_renderer_creation() {
let renderer = OpixaRenderer::new();
assert_eq!(renderer.name(), "opixa");
}
#[test]
fn test_opixa_render_with_real_font() {
let font = match load_font("NotoSans-Regular.ttf") {
Some(f) => f,
None => {
eprintln!("Skipping test: NotoSans-Regular.ttf not found");
return;
},
};
let renderer = OpixaRenderer::new();
let shaped = simple_shaping_result();
let params = RenderParams::default();
let result = renderer.render(&shaped, font, ¶ms);
assert!(result.is_ok(), "Render should succeed");
if let Ok(RenderOutput::Bitmap(bitmap)) = result {
assert_eq!(bitmap.format, BitmapFormat::Rgba8);
assert!(bitmap.width > 0, "Width should be positive");
assert!(bitmap.height > 0, "Height should be positive");
assert!(!bitmap.data.is_empty(), "Data should not be empty");
let expected_size = (bitmap.width * bitmap.height * 4) as usize;
assert_eq!(
bitmap.data.len(),
expected_size,
"Data size should match dimensions"
);
} else {
panic!("Expected bitmap output");
}
}
#[test]
fn test_opixa_render_empty_text() {
let font = match load_font("NotoSans-Regular.ttf") {
Some(f) => f,
None => return,
};
let renderer = OpixaRenderer::new();
let shaped = ShapingResult {
glyphs: vec![],
advance_width: 0.0,
advance_height: 200.0,
direction: Direction::LeftToRight,
};
let params = RenderParams::default();
let result = renderer.render(&shaped, font, ¶ms);
assert!(result.is_ok(), "Empty text should render successfully");
}
#[test]
fn test_opixa_render_different_sizes() {
let font = match load_font("NotoSans-Regular.ttf") {
Some(f) => f,
None => return,
};
let renderer = OpixaRenderer::new();
for size in [24.0, 48.0, 72.0, 200.0] {
let mut shaped = simple_shaping_result();
shaped.advance_height = size;
let params = RenderParams::default();
let result = renderer.render(&shaped, font.clone(), ¶ms);
assert!(result.is_ok(), "Size {} should render successfully", size);
if let Ok(RenderOutput::Bitmap(bitmap)) = result {
assert!(
bitmap.height > 0,
"Height should be positive for size {}",
size
);
}
}
}
#[test]
fn test_opixa_bitmap_hash_stability() {
let font = match load_font("NotoSans-Regular.ttf") {
Some(f) => f,
None => return,
};
let renderer = OpixaRenderer::new();
let shaped = simple_shaping_result();
let params = RenderParams::default();
let result1 = renderer
.render(&shaped, font.clone(), ¶ms)
.expect("First render should succeed");
let result2 = renderer
.render(&shaped, font, ¶ms)
.expect("Second render should succeed");
if let (RenderOutput::Bitmap(b1), RenderOutput::Bitmap(b2)) = (result1, result2) {
assert_eq!(b1.width, b2.width, "Width should be consistent");
assert_eq!(b1.height, b2.height, "Height should be consistent");
assert_eq!(b1.data, b2.data, "Bitmap data should be identical");
} else {
panic!("Expected bitmap outputs");
}
}
#[test]
fn test_opixa_supports_format() {
let renderer = OpixaRenderer::new();
assert!(renderer.supports_format("bitmap"));
assert!(renderer.supports_format("rgba"));
assert!(renderer.supports_format("rgb"));
assert!(renderer.supports_format("gray"));
assert!(!renderer.supports_format("svg")); assert!(!renderer.supports_format("png")); }