use alloc::sync::Arc;
use crate::{
ColorImage,
text::{FontFamily, FontPriority},
};
pub struct GlyphRasterizerRequest<'a> {
pub cluster: &'a str,
pub family: &'a FontFamily,
pub font_size_px: f32,
pub subpixel_offset_px: f32,
}
#[derive(Clone)]
pub struct GlyphBitmap {
pub image: ColorImage,
pub offset_px: emath::Vec2,
pub is_color: bool,
}
#[derive(Clone)]
pub struct RasterizedGlyph {
pub bitmap: GlyphBitmap,
pub advance_px: f32,
}
type RasterizeFn =
dyn for<'a> Fn(&GlyphRasterizerRequest<'a>) -> Option<RasterizedGlyph> + Send + Sync;
#[derive(Clone)]
pub struct GlyphRasterizer {
pub key: Arc<str>,
pub rasterize: Arc<RasterizeFn>,
pub priority: FontPriority,
}
impl GlyphRasterizer {
pub fn new(
key: impl Into<Arc<str>>,
rasterize: impl for<'a> Fn(&GlyphRasterizerRequest<'a>) -> Option<RasterizedGlyph>
+ Send
+ Sync
+ 'static,
) -> Self {
Self {
key: key.into(),
rasterize: Arc::new(rasterize),
priority: FontPriority::Lowest,
}
}
#[inline]
pub fn with_priority(mut self, priority: FontPriority) -> Self {
self.priority = priority;
self
}
#[doc(hidden)]
pub fn insert_into(self, rasterizers: &mut Vec<Self>) -> bool {
if rasterizers.iter().any(|r| r.key == self.key) {
false
} else {
rasterizers.push(self);
true
}
}
}
impl core::fmt::Debug for GlyphRasterizer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("GlyphRasterizer")
.field("priority", &self.priority)
.field("key", &self.key)
.finish_non_exhaustive()
}
}
pub fn has_emoji_presentation(cluster: &str) -> bool {
use unicode_properties::emoji::{
EmojiStatus, UnicodeEmoji as _, is_emoji_presentation_selector,
is_text_presentation_selector,
};
if cluster.is_ascii() {
return false; }
let mut has_emoji_presentation = false;
for c in cluster.chars() {
if is_text_presentation_selector(c) {
return false; }
has_emoji_presentation |= is_emoji_presentation_selector(c)
|| matches!(
c.emoji_status(),
EmojiStatus::EmojiPresentation
| EmojiStatus::EmojiPresentationAndModifierBase
| EmojiStatus::EmojiPresentationAndEmojiComponent
| EmojiStatus::EmojiPresentationAndModifierAndEmojiComponent
);
}
has_emoji_presentation
}
#[cfg(test)]
mod has_emoji_presentation_tests {
use super::has_emoji_presentation;
#[test]
fn emoji_presentation() {
for cluster in [
"😀",
"🦀",
"⏮\u{FE0F}", "☝🏻", "🇸🇪", "👨\u{200D}👩\u{200D}👧", "1\u{FE0F}\u{20E3}", ] {
assert!(has_emoji_presentation(cluster), "{cluster:?}");
}
}
#[test]
fn text_presentation() {
for cluster in [
"",
"a",
"1",
"⏮",
"⏮\u{FE0E}", "😀\u{FE0E}", "✔",
"♥",
"©",
"→",
"√",
] {
assert!(!has_emoji_presentation(cluster), "{cluster:?}");
}
}
}