Make FontSystem global and simplify Paragraph API
This commit is contained in:
parent
9245423c5d
commit
346af3f8b0
15 changed files with 165 additions and 328 deletions
|
|
@ -25,16 +25,15 @@ iced_core.workspace = true
|
|||
|
||||
bitflags.workspace = true
|
||||
bytemuck.workspace = true
|
||||
cosmic-text.workspace = true
|
||||
glam.workspace = true
|
||||
half.workspace = true
|
||||
log.workspace = true
|
||||
once_cell.workspace = true
|
||||
raw-window-handle.workspace = true
|
||||
thiserror.workspace = true
|
||||
cosmic-text.workspace = true
|
||||
rustc-hash.workspace = true
|
||||
|
||||
lyon_path.workspace = true
|
||||
lyon_path.optional = true
|
||||
thiserror.workspace = true
|
||||
twox-hash.workspace = true
|
||||
|
||||
image.workspace = true
|
||||
image.optional = true
|
||||
|
|
@ -42,7 +41,8 @@ image.optional = true
|
|||
kamadak-exif.workspace = true
|
||||
kamadak-exif.optional = true
|
||||
|
||||
twox-hash.workspace = true
|
||||
lyon_path.workspace = true
|
||||
lyon_path.optional = true
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
twox-hash.workspace = true
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
use crate::core::image;
|
||||
use crate::core::svg;
|
||||
use crate::core::Size;
|
||||
use crate::text;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
|
@ -18,9 +17,6 @@ pub trait Backend {
|
|||
pub trait Text {
|
||||
/// Loads a font from its bytes.
|
||||
fn load_font(&mut self, font: Cow<'static, [u8]>);
|
||||
|
||||
/// Returns the [`cosmic_text::FontSystem`] of the [`Backend`].
|
||||
fn font_system(&self) -> &text::FontSystem;
|
||||
}
|
||||
|
||||
/// A graphics backend that supports image rendering.
|
||||
|
|
|
|||
|
|
@ -158,41 +158,6 @@ where
|
|||
self.backend.load_font(bytes);
|
||||
}
|
||||
|
||||
fn create_paragraph(&self, text: Text<'_, Self::Font>) -> text::Paragraph {
|
||||
text::Paragraph::with_text(text, self.backend.font_system())
|
||||
}
|
||||
|
||||
fn update_paragraph(
|
||||
&self,
|
||||
paragraph: &mut Self::Paragraph,
|
||||
text: Text<'_, Self::Font>,
|
||||
) {
|
||||
let font_system = self.backend.font_system();
|
||||
|
||||
if paragraph.version() != font_system.version() {
|
||||
// The font system has changed, paragraph fonts may be outdated
|
||||
*paragraph = self.create_paragraph(text);
|
||||
} else {
|
||||
match core::text::compare(paragraph, text) {
|
||||
core::text::Difference::None => {}
|
||||
core::text::Difference::Bounds => {
|
||||
self.resize_paragraph(paragraph, text.bounds);
|
||||
}
|
||||
core::text::Difference::Shape => {
|
||||
*paragraph = self.create_paragraph(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resize_paragraph(
|
||||
&self,
|
||||
paragraph: &mut Self::Paragraph,
|
||||
new_bounds: Size,
|
||||
) {
|
||||
paragraph.resize(new_bounds, self.backend.font_system());
|
||||
}
|
||||
|
||||
fn fill_paragraph(
|
||||
&mut self,
|
||||
paragraph: &Self::Paragraph,
|
||||
|
|
|
|||
|
|
@ -10,40 +10,39 @@ use crate::core::font::{self, Font};
|
|||
use crate::core::text::Shaping;
|
||||
use crate::core::Size;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::borrow::Cow;
|
||||
use std::sync::{self, Arc, RwLock};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct FontSystem {
|
||||
raw: RwLock<cosmic_text::FontSystem>,
|
||||
version: Version,
|
||||
}
|
||||
pub fn font_system() -> &'static RwLock<FontSystem> {
|
||||
static FONT_SYSTEM: OnceCell<RwLock<FontSystem>> = OnceCell::new();
|
||||
|
||||
impl FontSystem {
|
||||
pub fn new() -> Self {
|
||||
FontSystem {
|
||||
raw: RwLock::new(cosmic_text::FontSystem::new_with_fonts(
|
||||
FONT_SYSTEM.get_or_init(|| {
|
||||
RwLock::new(FontSystem {
|
||||
raw: cosmic_text::FontSystem::new_with_fonts(
|
||||
[cosmic_text::fontdb::Source::Binary(Arc::new(
|
||||
include_bytes!("../fonts/Iced-Icons.ttf").as_slice(),
|
||||
))]
|
||||
.into_iter(),
|
||||
)),
|
||||
),
|
||||
version: Version::default(),
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self) -> &mut cosmic_text::FontSystem {
|
||||
self.raw.get_mut().expect("Lock font system")
|
||||
}
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct FontSystem {
|
||||
raw: cosmic_text::FontSystem,
|
||||
version: Version,
|
||||
}
|
||||
|
||||
pub fn write(
|
||||
&self,
|
||||
) -> (sync::RwLockWriteGuard<'_, cosmic_text::FontSystem>, Version) {
|
||||
(self.raw.write().expect("Write font system"), self.version)
|
||||
impl FontSystem {
|
||||
pub fn raw(&mut self) -> &mut cosmic_text::FontSystem {
|
||||
&mut self.raw
|
||||
}
|
||||
|
||||
pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) {
|
||||
let _ = self.get_mut().db_mut().load_font_source(
|
||||
let _ = self.raw.db_mut().load_font_source(
|
||||
cosmic_text::fontdb::Source::Binary(Arc::new(bytes.into_owned())),
|
||||
);
|
||||
|
||||
|
|
@ -58,12 +57,6 @@ impl FontSystem {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct Version(u32);
|
||||
|
||||
impl Default for FontSystem {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn measure(buffer: &cosmic_text::Buffer) -> Size {
|
||||
let (width, total_lines) = buffer
|
||||
.layout_runs()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::core;
|
|||
use crate::core::alignment;
|
||||
use crate::core::text::{Hit, LineHeight, Shaping, Text};
|
||||
use crate::core::{Font, Pixels, Point, Size};
|
||||
use crate::text::{self, FontSystem};
|
||||
use crate::text;
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::{self, Arc};
|
||||
|
|
@ -27,13 +27,39 @@ impl Paragraph {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
pub fn with_text(text: Text<'_, Font>, font_system: &FontSystem) -> Self {
|
||||
pub fn buffer(&self) -> &cosmic_text::Buffer {
|
||||
&self.internal().buffer
|
||||
}
|
||||
|
||||
pub fn downgrade(&self) -> Weak {
|
||||
let paragraph = self.internal();
|
||||
|
||||
Weak {
|
||||
raw: Arc::downgrade(paragraph),
|
||||
min_bounds: paragraph.min_bounds,
|
||||
horizontal_alignment: paragraph.horizontal_alignment,
|
||||
vertical_alignment: paragraph.vertical_alignment,
|
||||
}
|
||||
}
|
||||
|
||||
fn internal(&self) -> &Arc<Internal> {
|
||||
self.0
|
||||
.as_ref()
|
||||
.expect("paragraph should always be initialized")
|
||||
}
|
||||
}
|
||||
|
||||
impl core::text::Paragraph for Paragraph {
|
||||
type Font = Font;
|
||||
|
||||
fn with_text(text: Text<'_, Font>) -> Self {
|
||||
log::trace!("Allocating paragraph: {}", text.content);
|
||||
|
||||
let (mut font_system, version) = font_system.write();
|
||||
let mut font_system =
|
||||
text::font_system().write().expect("Write font system");
|
||||
|
||||
let mut buffer = cosmic_text::Buffer::new(
|
||||
&mut font_system,
|
||||
font_system.raw(),
|
||||
cosmic_text::Metrics::new(
|
||||
text.size.into(),
|
||||
text.line_height.to_absolute(text.size).into(),
|
||||
|
|
@ -41,13 +67,13 @@ impl Paragraph {
|
|||
);
|
||||
|
||||
buffer.set_size(
|
||||
&mut font_system,
|
||||
font_system.raw(),
|
||||
text.bounds.width,
|
||||
text.bounds.height,
|
||||
);
|
||||
|
||||
buffer.set_text(
|
||||
&mut font_system,
|
||||
font_system.raw(),
|
||||
text.content,
|
||||
text::to_attributes(text.font),
|
||||
text::to_shaping(text.shaping),
|
||||
|
|
@ -64,30 +90,11 @@ impl Paragraph {
|
|||
shaping: text.shaping,
|
||||
bounds: text.bounds,
|
||||
min_bounds,
|
||||
version,
|
||||
version: font_system.version(),
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &cosmic_text::Buffer {
|
||||
&self.internal().buffer
|
||||
}
|
||||
|
||||
pub fn version(&self) -> text::Version {
|
||||
self.internal().version
|
||||
}
|
||||
|
||||
pub fn downgrade(&self) -> Weak {
|
||||
let paragraph = self.internal();
|
||||
|
||||
Weak {
|
||||
raw: Arc::downgrade(paragraph),
|
||||
min_bounds: paragraph.min_bounds,
|
||||
horizontal_alignment: paragraph.horizontal_alignment,
|
||||
vertical_alignment: paragraph.vertical_alignment,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, new_bounds: Size, font_system: &FontSystem) {
|
||||
fn resize(&mut self, new_bounds: Size) {
|
||||
let paragraph = self
|
||||
.0
|
||||
.take()
|
||||
|
|
@ -95,10 +102,11 @@ impl Paragraph {
|
|||
|
||||
match Arc::try_unwrap(paragraph) {
|
||||
Ok(mut internal) => {
|
||||
let (mut font_system, _) = font_system.write();
|
||||
let mut font_system =
|
||||
text::font_system().write().expect("Write font system");
|
||||
|
||||
internal.buffer.set_size(
|
||||
&mut font_system,
|
||||
font_system.raw(),
|
||||
new_bounds.width,
|
||||
new_bounds.height,
|
||||
);
|
||||
|
|
@ -113,55 +121,42 @@ impl Paragraph {
|
|||
|
||||
// If there is a strong reference somewhere, we recompute the
|
||||
// buffer from scratch
|
||||
*self = Self::with_text(
|
||||
Text {
|
||||
content: &internal.content,
|
||||
bounds: internal.bounds,
|
||||
size: Pixels(metrics.font_size),
|
||||
line_height: LineHeight::Absolute(Pixels(
|
||||
metrics.line_height,
|
||||
)),
|
||||
font: internal.font,
|
||||
horizontal_alignment: internal.horizontal_alignment,
|
||||
vertical_alignment: internal.vertical_alignment,
|
||||
shaping: internal.shaping,
|
||||
},
|
||||
font_system,
|
||||
);
|
||||
*self = Self::with_text(Text {
|
||||
content: &internal.content,
|
||||
bounds: internal.bounds,
|
||||
size: Pixels(metrics.font_size),
|
||||
line_height: LineHeight::Absolute(Pixels(
|
||||
metrics.line_height,
|
||||
)),
|
||||
font: internal.font,
|
||||
horizontal_alignment: internal.horizontal_alignment,
|
||||
vertical_alignment: internal.vertical_alignment,
|
||||
shaping: internal.shaping,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn internal(&self) -> &Arc<Internal> {
|
||||
self.0
|
||||
.as_ref()
|
||||
.expect("paragraph should always be initialized")
|
||||
}
|
||||
}
|
||||
fn compare(&self, text: Text<'_, Font>) -> core::text::Difference {
|
||||
let font_system = text::font_system().read().expect("Read font system");
|
||||
let paragraph = self.internal();
|
||||
let metrics = paragraph.buffer.metrics();
|
||||
|
||||
impl core::text::Paragraph for Paragraph {
|
||||
type Font = Font;
|
||||
|
||||
fn content(&self) -> &str {
|
||||
&self.internal().content
|
||||
}
|
||||
|
||||
fn text_size(&self) -> Pixels {
|
||||
Pixels(self.internal().buffer.metrics().font_size)
|
||||
}
|
||||
|
||||
fn line_height(&self) -> LineHeight {
|
||||
LineHeight::Absolute(Pixels(
|
||||
self.internal().buffer.metrics().line_height,
|
||||
))
|
||||
}
|
||||
|
||||
fn font(&self) -> Font {
|
||||
self.internal().font
|
||||
}
|
||||
|
||||
fn shaping(&self) -> Shaping {
|
||||
self.internal().shaping
|
||||
if paragraph.version != font_system.version
|
||||
|| paragraph.content != text.content
|
||||
|| metrics.font_size != text.size.0
|
||||
|| metrics.line_height != text.line_height.to_absolute(text.size).0
|
||||
|| paragraph.font != text.font
|
||||
|| paragraph.shaping != text.shaping
|
||||
|| paragraph.horizontal_alignment != text.horizontal_alignment
|
||||
|| paragraph.vertical_alignment != text.vertical_alignment
|
||||
{
|
||||
core::text::Difference::Shape
|
||||
} else if paragraph.bounds != text.bounds {
|
||||
core::text::Difference::Bounds
|
||||
} else {
|
||||
core::text::Difference::None
|
||||
}
|
||||
}
|
||||
|
||||
fn horizontal_alignment(&self) -> alignment::Horizontal {
|
||||
|
|
@ -172,10 +167,6 @@ impl core::text::Paragraph for Paragraph {
|
|||
self.internal().vertical_alignment
|
||||
}
|
||||
|
||||
fn bounds(&self) -> Size {
|
||||
self.internal().bounds
|
||||
}
|
||||
|
||||
fn min_bounds(&self) -> Size {
|
||||
self.internal().min_bounds
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue