use std::cell::RefCell;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use crate::text::Font;
static TYPOGRAPHY_EPOCH: AtomicU64 = AtomicU64::new(1);
pub fn current_typography_epoch() -> u64 {
TYPOGRAPHY_EPOCH.load(Ordering::Relaxed)
}
fn bump_typography_epoch() {
TYPOGRAPHY_EPOCH.fetch_add(1, Ordering::Relaxed);
}
thread_local! {
static SYSTEM_FONT: RefCell<Option<Arc<Font>>> = RefCell::new(None);
static FONT_SIZE_SCALE: RefCell<f64> = RefCell::new(1.0);
static LCD_ENABLED: RefCell<Option<bool>> = const { RefCell::new(None) };
static HINTING_ENABLED: RefCell<bool> = RefCell::new(false);
static GAMMA: RefCell<f64> = RefCell::new(1.0);
static WIDTH: RefCell<f64> = RefCell::new(1.0);
static INTERVAL: RefCell<f64> = RefCell::new(0.0);
static FAUX_WEIGHT: RefCell<f64> = RefCell::new(0.0);
static FAUX_ITALIC: RefCell<f64> = RefCell::new(0.0);
static PRIMARY_WEIGHT: RefCell<f64> = RefCell::new(1.0 / 3.0);
}
pub fn current_system_font() -> Option<Arc<Font>> {
SYSTEM_FONT.with(|c| c.borrow().clone())
}
pub fn set_system_font(font: Option<Arc<Font>>) {
SYSTEM_FONT.with(|c| *c.borrow_mut() = font);
bump_typography_epoch();
}
pub fn current_font_size_scale() -> f64 {
FONT_SIZE_SCALE.with(|c| *c.borrow())
}
pub fn set_font_size_scale(scale: f64) {
let clamped = scale.clamp(0.5, 3.0);
FONT_SIZE_SCALE.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
pub fn lcd_enabled() -> bool {
if crate::ux_scale::effective_scale() > 1.25 {
return false;
}
if let Some(explicit) = LCD_ENABLED.with(|c| *c.borrow()) {
return explicit;
}
true
}
pub fn set_lcd_enabled(on: bool) {
LCD_ENABLED.with(|c| *c.borrow_mut() = Some(on));
bump_typography_epoch();
}
pub fn clear_lcd_enabled_override() {
LCD_ENABLED.with(|c| *c.borrow_mut() = None);
bump_typography_epoch();
}
pub fn hinting_enabled() -> bool {
HINTING_ENABLED.with(|c| *c.borrow())
}
pub fn set_hinting_enabled(on: bool) {
HINTING_ENABLED.with(|c| *c.borrow_mut() = on);
bump_typography_epoch();
}
pub fn current_gamma() -> f64 {
GAMMA.with(|c| *c.borrow())
}
pub fn set_gamma(v: f64) {
let clamped = v.clamp(0.5, 2.5);
GAMMA.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
pub fn current_width() -> f64 {
WIDTH.with(|c| *c.borrow())
}
pub fn set_width(v: f64) {
let clamped = v.clamp(0.75, 1.25);
WIDTH.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
pub fn current_interval() -> f64 {
INTERVAL.with(|c| *c.borrow())
}
pub fn set_interval(v: f64) {
let clamped = v.clamp(-0.2, 0.2);
INTERVAL.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
pub fn current_faux_weight() -> f64 {
FAUX_WEIGHT.with(|c| *c.borrow())
}
pub fn set_faux_weight(v: f64) {
let clamped = v.clamp(-1.0, 1.0);
FAUX_WEIGHT.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
pub fn current_faux_italic() -> f64 {
FAUX_ITALIC.with(|c| *c.borrow())
}
pub fn set_faux_italic(v: f64) {
let clamped = v.clamp(-1.0, 1.0);
FAUX_ITALIC.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
pub fn current_primary_weight() -> f64 {
PRIMARY_WEIGHT.with(|c| *c.borrow())
}
pub fn set_primary_weight(v: f64) {
let clamped = v.clamp(0.0, 1.0);
PRIMARY_WEIGHT.with(|c| *c.borrow_mut() = clamped);
bump_typography_epoch();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lcd_flag_explicit_override_round_trips() {
crate::device_scale::set_device_scale(1.0);
crate::ux_scale::set_ux_scale(1.0);
set_lcd_enabled(false);
assert!(!lcd_enabled());
set_lcd_enabled(true);
assert!(lcd_enabled());
clear_lcd_enabled_override();
}
#[test]
fn test_lcd_flag_auto_derives_from_device_scale_when_no_override() {
use crate::device_scale::set_device_scale;
clear_lcd_enabled_override();
set_device_scale(1.0);
assert!(lcd_enabled(), "standard DPI should default to LCD on");
set_device_scale(2.0);
assert!(!lcd_enabled(), "HiDPI should default to LCD off");
set_device_scale(1.0);
}
#[test]
fn test_lcd_auto_disabled_at_high_effective_scale_from_ux_zoom() {
use crate::device_scale::set_device_scale;
use crate::ux_scale::set_ux_scale;
clear_lcd_enabled_override();
set_device_scale(1.0);
set_ux_scale(1.0);
assert!(lcd_enabled(), "standard DPI + no zoom should default to LCD on");
set_ux_scale(1.7);
assert!(
!lcd_enabled(),
"high effective scale via ux zoom should default to LCD off"
);
set_lcd_enabled(true);
assert!(
!lcd_enabled(),
"explicit LCD-on override must still be capped off at high effective scale"
);
set_ux_scale(1.0);
assert!(lcd_enabled(), "override LCD-on must apply at standard density");
clear_lcd_enabled_override();
set_ux_scale(1.0);
set_device_scale(1.0);
}
#[test]
fn test_hinting_flag_default_off() {
set_hinting_enabled(false);
assert!(!hinting_enabled());
set_hinting_enabled(true);
assert!(hinting_enabled());
set_hinting_enabled(false);
}
#[test]
fn test_system_font_default_none() {
set_system_font(None);
assert!(current_system_font().is_none());
}
}