use std::marker::PhantomData;
use slate_renderer::atlas::Atlas;
use slate_renderer::scene::GlyphInstance;
use slate_text::backend::Font;
use slate_text::run_builder::TextRunBuilder;
use slate_text::types::ShapedLine;
use slate_text::{GlyphCache, TextError};
#[cfg(target_os = "macos")]
use slate_text::CoreTextBackend;
#[cfg(target_os = "windows")]
use slate_text::DirectWriteBackend;
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
compile_error!(
"slate-framework currently supports macOS and Windows only. Linux support is planned for a future release."
);
pub struct TextSystem {
#[cfg(target_os = "macos")]
backend: CoreTextBackend,
#[cfg(target_os = "windows")]
backend: DirectWriteBackend,
_not_send: PhantomData<*const ()>,
}
impl TextSystem {
pub fn new() -> Result<Self, TextError> {
Ok(Self {
#[cfg(target_os = "macos")]
backend: CoreTextBackend::new()?,
#[cfg(target_os = "windows")]
backend: DirectWriteBackend::new()?,
_not_send: PhantomData,
})
}
pub fn load_font(
&mut self,
family: &str,
size_lpx: f32,
scale: f32,
) -> Result<PlatformFont, TextError> {
use slate_text::TextBackend;
let inner = self.backend.load_font(family, size_lpx, scale)?;
Ok(PlatformFont {
inner,
_not_send: PhantomData,
})
}
pub fn load_font_from_bytes(
&mut self,
bytes: &'static [u8],
size_lpx: f32,
scale: f32,
) -> Result<PlatformFont, TextError> {
use slate_text::TextBackend;
let inner = self.backend.load_font_from_bytes(bytes, size_lpx, scale)?;
Ok(PlatformFont {
inner,
_not_send: PhantomData,
})
}
pub fn shape_line(&self, font: &PlatformFont, text: &str) -> Result<ShapedLine, TextError> {
use slate_text::TextBackend;
self.backend.shape_line(&font.inner, text)
}
pub fn shape_line_bidi(
&self,
font: &PlatformFont,
text: &str,
) -> Result<ShapedLine, TextError> {
slate_text::shape_line_bidi(&self.backend, &font.inner, text)
}
pub fn shape_words(
&self,
font: &PlatformFont,
text: &str,
) -> Result<(Vec<slate_text::ShapedWord>, f32), TextError> {
slate_text::shape_words(&self.backend, &font.inner, text)
}
pub fn shape_document(
&self,
font: &PlatformFont,
text: &str,
) -> Result<slate_text::ShapedDocument, TextError> {
slate_text::shape_document(&self.backend, &font.inner, text)
}
pub fn measure_text(&self, font: &PlatformFont, text: &str) -> Result<(f32, f32), TextError> {
let shaped = self.shape_line(font, text)?;
Ok((shaped.width_lpx, shaped.ascent_lpx - shaped.descent_lpx))
}
#[allow(clippy::too_many_arguments)]
pub fn rasterize_text_run(
&self,
font: &PlatformFont,
shaped: &ShapedLine,
baseline_lpx: [f32; 2],
color: [f32; 4],
glyph_cache: &mut GlyphCache,
atlas: &mut Atlas,
queue: &wgpu::Queue,
) -> Result<Vec<GlyphInstance>, TextError> {
let builder = TextRunBuilder {
backend: &self.backend,
font: &font.inner,
baseline_lpx,
color,
};
builder.build(shaped, glyph_cache, atlas, queue)
}
}
pub struct PlatformFont {
#[cfg(target_os = "macos")]
pub(crate) inner: <CoreTextBackend as slate_text::TextBackend>::Font,
#[cfg(target_os = "windows")]
pub(crate) inner: <DirectWriteBackend as slate_text::TextBackend>::Font,
_not_send: PhantomData<*const ()>,
}
impl PlatformFont {
pub fn metrics(&self) -> slate_text::types::FontMetrics {
self.inner.metrics()
}
pub fn size_lpx(&self) -> f32 {
self.inner.size_lpx()
}
pub fn scale(&self) -> f32 {
self.inner.scale()
}
}