Make CosmicFontSystem and SwashCache pub resources. (#15479)
# Objective In nannou, we'd like to be able to access the [outline commands](https://docs.rs/cosmic-text/latest/cosmic_text/struct.SwashCache.html#method.get_outline_commands) from swash, while still benefit from Bevy's management of font assets. ## Solution Make `CosmicFontSystem` and `SwashCache` pub resources. ## Testing Ran some examples.
This commit is contained in:
parent
9b4d2de215
commit
df23b937cc
@ -109,7 +109,9 @@ impl Plugin for TextPlugin {
|
|||||||
.register_type::<TextBounds>()
|
.register_type::<TextBounds>()
|
||||||
.init_asset_loader::<FontLoader>()
|
.init_asset_loader::<FontLoader>()
|
||||||
.init_resource::<FontAtlasSets>()
|
.init_resource::<FontAtlasSets>()
|
||||||
.insert_resource(TextPipeline::default())
|
.init_resource::<TextPipeline>()
|
||||||
|
.init_resource::<CosmicFontSystem>()
|
||||||
|
.init_resource::<SwashCache>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
(
|
(
|
||||||
|
|||||||
@ -20,8 +20,13 @@ use crate::{
|
|||||||
PositionedGlyph, TextBounds, TextSection, YAxisOrientation,
|
PositionedGlyph, TextBounds, TextSection, YAxisOrientation,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A wrapper around a [`cosmic_text::FontSystem`]
|
/// A wrapper resource around a [`cosmic_text::FontSystem`]
|
||||||
struct CosmicFontSystem(cosmic_text::FontSystem);
|
///
|
||||||
|
/// The font system is used to retrieve fonts and their information, including glyph outlines.
|
||||||
|
///
|
||||||
|
/// This resource is updated by the [`TextPipeline`] resource.
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct CosmicFontSystem(pub cosmic_text::FontSystem);
|
||||||
|
|
||||||
impl Default for CosmicFontSystem {
|
impl Default for CosmicFontSystem {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -32,8 +37,13 @@ impl Default for CosmicFontSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a [`cosmic_text::SwashCache`]
|
/// A wrapper resource around a [`cosmic_text::SwashCache`]
|
||||||
struct SwashCache(cosmic_text::SwashCache);
|
///
|
||||||
|
/// The swash cache rasterizer is used to rasterize glyphs
|
||||||
|
///
|
||||||
|
/// This resource is updated by the [`TextPipeline`] resource.
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct SwashCache(pub cosmic_text::SwashCache);
|
||||||
|
|
||||||
impl Default for SwashCache {
|
impl Default for SwashCache {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -48,14 +58,6 @@ impl Default for SwashCache {
|
|||||||
pub struct TextPipeline {
|
pub struct TextPipeline {
|
||||||
/// Identifies a font [`ID`](cosmic_text::fontdb::ID) by its [`Font`] [`Asset`](bevy_asset::Asset).
|
/// Identifies a font [`ID`](cosmic_text::fontdb::ID) by its [`Font`] [`Asset`](bevy_asset::Asset).
|
||||||
map_handle_to_font_id: HashMap<AssetId<Font>, (cosmic_text::fontdb::ID, String)>,
|
map_handle_to_font_id: HashMap<AssetId<Font>, (cosmic_text::fontdb::ID, String)>,
|
||||||
/// The font system is used to retrieve fonts and their information, including glyph outlines.
|
|
||||||
///
|
|
||||||
/// See [`cosmic_text::FontSystem`] for more information.
|
|
||||||
font_system: CosmicFontSystem,
|
|
||||||
/// The swash cache rasterizer is used to rasterize glyphs
|
|
||||||
///
|
|
||||||
/// See [`cosmic_text::SwashCache`] for more information.
|
|
||||||
swash_cache: SwashCache,
|
|
||||||
/// Buffered vec for collecting spans.
|
/// Buffered vec for collecting spans.
|
||||||
///
|
///
|
||||||
/// See [this dark magic](https://users.rust-lang.org/t/how-to-cache-a-vectors-capacity/94478/10).
|
/// See [this dark magic](https://users.rust-lang.org/t/how-to-cache-a-vectors-capacity/94478/10).
|
||||||
@ -76,8 +78,9 @@ impl TextPipeline {
|
|||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
buffer: &mut CosmicBuffer,
|
buffer: &mut CosmicBuffer,
|
||||||
alignment: JustifyText,
|
alignment: JustifyText,
|
||||||
|
font_system: &mut CosmicFontSystem,
|
||||||
) -> Result<(), TextError> {
|
) -> Result<(), TextError> {
|
||||||
let font_system = &mut self.font_system.0;
|
let font_system = &mut font_system.0;
|
||||||
|
|
||||||
// return early if the fonts are not loaded yet
|
// return early if the fonts are not loaded yet
|
||||||
let mut font_size = 0.;
|
let mut font_size = 0.;
|
||||||
@ -188,6 +191,8 @@ impl TextPipeline {
|
|||||||
textures: &mut Assets<Image>,
|
textures: &mut Assets<Image>,
|
||||||
y_axis_orientation: YAxisOrientation,
|
y_axis_orientation: YAxisOrientation,
|
||||||
buffer: &mut CosmicBuffer,
|
buffer: &mut CosmicBuffer,
|
||||||
|
font_system: &mut CosmicFontSystem,
|
||||||
|
swash_cache: &mut SwashCache,
|
||||||
) -> Result<(), TextError> {
|
) -> Result<(), TextError> {
|
||||||
layout_info.glyphs.clear();
|
layout_info.glyphs.clear();
|
||||||
layout_info.size = Default::default();
|
layout_info.size = Default::default();
|
||||||
@ -204,11 +209,10 @@ impl TextPipeline {
|
|||||||
scale_factor,
|
scale_factor,
|
||||||
buffer,
|
buffer,
|
||||||
text_alignment,
|
text_alignment,
|
||||||
|
font_system,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let box_size = buffer_dimensions(buffer);
|
let box_size = buffer_dimensions(buffer);
|
||||||
let font_system = &mut self.font_system.0;
|
|
||||||
let swash_cache = &mut self.swash_cache.0;
|
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
.layout_runs()
|
.layout_runs()
|
||||||
@ -250,8 +254,8 @@ impl TextPipeline {
|
|||||||
font_atlas_set.add_glyph_to_atlas(
|
font_atlas_set.add_glyph_to_atlas(
|
||||||
texture_atlases,
|
texture_atlases,
|
||||||
textures,
|
textures,
|
||||||
font_system,
|
&mut font_system.0,
|
||||||
swash_cache,
|
&mut swash_cache.0,
|
||||||
layout_glyph,
|
layout_glyph,
|
||||||
font_smoothing,
|
font_smoothing,
|
||||||
)
|
)
|
||||||
@ -300,6 +304,7 @@ impl TextPipeline {
|
|||||||
linebreak_behavior: BreakLineOn,
|
linebreak_behavior: BreakLineOn,
|
||||||
buffer: &mut CosmicBuffer,
|
buffer: &mut CosmicBuffer,
|
||||||
text_alignment: JustifyText,
|
text_alignment: JustifyText,
|
||||||
|
font_system: &mut CosmicFontSystem,
|
||||||
) -> Result<TextMeasureInfo, TextError> {
|
) -> Result<TextMeasureInfo, TextError> {
|
||||||
const MIN_WIDTH_CONTENT_BOUNDS: TextBounds = TextBounds::new_horizontal(0.0);
|
const MIN_WIDTH_CONTENT_BOUNDS: TextBounds = TextBounds::new_horizontal(0.0);
|
||||||
|
|
||||||
@ -311,12 +316,13 @@ impl TextPipeline {
|
|||||||
scale_factor,
|
scale_factor,
|
||||||
buffer,
|
buffer,
|
||||||
text_alignment,
|
text_alignment,
|
||||||
|
font_system,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let min_width_content_size = buffer_dimensions(buffer);
|
let min_width_content_size = buffer_dimensions(buffer);
|
||||||
|
|
||||||
let max_width_content_size = {
|
let max_width_content_size = {
|
||||||
let font_system = &mut self.font_system.0;
|
let font_system = &mut font_system.0;
|
||||||
buffer.set_size(font_system, None, None);
|
buffer.set_size(font_system, None, None);
|
||||||
buffer_dimensions(buffer)
|
buffer_dimensions(buffer)
|
||||||
};
|
};
|
||||||
@ -328,11 +334,12 @@ impl TextPipeline {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to the [`cosmic_text::FontSystem`].
|
/// Returns the [`cosmic_text::fontdb::ID`] for a given [`Font`] asset.
|
||||||
///
|
pub fn get_font_id(&self, asset_id: AssetId<Font>) -> Option<cosmic_text::fontdb::ID> {
|
||||||
/// Used internally.
|
self.map_handle_to_font_id
|
||||||
pub fn font_system_mut(&mut self) -> &mut cosmic_text::FontSystem {
|
.get(&asset_id)
|
||||||
&mut self.font_system.0
|
.cloned()
|
||||||
|
.map(|(id, _)| id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,11 +449,11 @@ fn buffer_dimensions(buffer: &Buffer) -> Vec2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Discards stale data cached in `FontSystem`.
|
/// Discards stale data cached in `FontSystem`.
|
||||||
pub(crate) fn trim_cosmic_cache(mut pipeline: ResMut<TextPipeline>) {
|
pub(crate) fn trim_cosmic_cache(mut font_system: ResMut<CosmicFontSystem>) {
|
||||||
// A trim age of 2 was found to reduce frame time variance vs age of 1 when tested with dynamic text.
|
// A trim age of 2 was found to reduce frame time variance vs age of 1 when tested with dynamic text.
|
||||||
// See https://github.com/bevyengine/bevy/pull/15037
|
// See https://github.com/bevyengine/bevy/pull/15037
|
||||||
//
|
//
|
||||||
// We assume only text updated frequently benefits from the shape cache (e.g. animated text, or
|
// We assume only text updated frequently benefits from the shape cache (e.g. animated text, or
|
||||||
// text that is dynamically measured for UI).
|
// text that is dynamically measured for UI).
|
||||||
pipeline.font_system_mut().shape_run_cache.trim(2);
|
font_system.0.shape_run_cache.trim(2);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
|
use crate::pipeline::CosmicFontSystem;
|
||||||
use crate::{
|
use crate::{
|
||||||
BreakLineOn, CosmicBuffer, Font, FontAtlasSets, PositionedGlyph, Text, TextBounds, TextError,
|
BreakLineOn, CosmicBuffer, Font, FontAtlasSets, PositionedGlyph, SwashCache, Text, TextBounds,
|
||||||
TextLayoutInfo, TextPipeline, YAxisOrientation,
|
TextError, TextLayoutInfo, TextPipeline, YAxisOrientation,
|
||||||
};
|
};
|
||||||
use bevy_asset::Assets;
|
use bevy_asset::Assets;
|
||||||
use bevy_color::LinearRgba;
|
use bevy_color::LinearRgba;
|
||||||
@ -158,6 +159,8 @@ pub fn update_text2d_layout(
|
|||||||
&mut TextLayoutInfo,
|
&mut TextLayoutInfo,
|
||||||
&mut CosmicBuffer,
|
&mut CosmicBuffer,
|
||||||
)>,
|
)>,
|
||||||
|
mut font_system: ResMut<CosmicFontSystem>,
|
||||||
|
mut swash_cache: ResMut<SwashCache>,
|
||||||
) {
|
) {
|
||||||
// We need to consume the entire iterator, hence `last`
|
// We need to consume the entire iterator, hence `last`
|
||||||
let factor_changed = scale_factor_changed.read().last().is_some();
|
let factor_changed = scale_factor_changed.read().last().is_some();
|
||||||
@ -198,6 +201,8 @@ pub fn update_text2d_layout(
|
|||||||
&mut textures,
|
&mut textures,
|
||||||
YAxisOrientation::BottomToTop,
|
YAxisOrientation::BottomToTop,
|
||||||
buffer.as_mut(),
|
buffer.as_mut(),
|
||||||
|
&mut font_system,
|
||||||
|
&mut swash_cache,
|
||||||
) {
|
) {
|
||||||
Err(TextError::NoSuchFont) => {
|
Err(TextError::NoSuchFont) => {
|
||||||
// There was an error processing the text layout, let's add this entity to the
|
// There was an error processing the text layout, let's add this entity to the
|
||||||
@ -274,7 +279,9 @@ mod tests {
|
|||||||
.init_resource::<Assets<TextureAtlasLayout>>()
|
.init_resource::<Assets<TextureAtlasLayout>>()
|
||||||
.init_resource::<FontAtlasSets>()
|
.init_resource::<FontAtlasSets>()
|
||||||
.init_resource::<Events<WindowScaleFactorChanged>>()
|
.init_resource::<Events<WindowScaleFactorChanged>>()
|
||||||
.insert_resource(TextPipeline::default())
|
.init_resource::<TextPipeline>()
|
||||||
|
.init_resource::<CosmicFontSystem>()
|
||||||
|
.init_resource::<SwashCache>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
|
|||||||
@ -22,7 +22,9 @@ use thiserror::Error;
|
|||||||
use ui_surface::UiSurface;
|
use ui_surface::UiSurface;
|
||||||
|
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
use bevy_text::{CosmicBuffer, TextPipeline};
|
use bevy_text::CosmicBuffer;
|
||||||
|
#[cfg(feature = "bevy_text")]
|
||||||
|
use bevy_text::CosmicFontSystem;
|
||||||
|
|
||||||
mod convert;
|
mod convert;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
@ -124,7 +126,7 @@ pub fn ui_layout_system(
|
|||||||
Option<&ScrollPosition>,
|
Option<&ScrollPosition>,
|
||||||
)>,
|
)>,
|
||||||
#[cfg(feature = "bevy_text")] mut buffer_query: Query<&mut CosmicBuffer>,
|
#[cfg(feature = "bevy_text")] mut buffer_query: Query<&mut CosmicBuffer>,
|
||||||
#[cfg(feature = "bevy_text")] mut text_pipeline: ResMut<TextPipeline>,
|
#[cfg(feature = "bevy_text")] mut font_system: ResMut<CosmicFontSystem>,
|
||||||
) {
|
) {
|
||||||
let UiLayoutSystemBuffers {
|
let UiLayoutSystemBuffers {
|
||||||
interned_root_nodes,
|
interned_root_nodes,
|
||||||
@ -250,8 +252,6 @@ pub fn ui_layout_system(
|
|||||||
|
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
let text_buffers = &mut buffer_query;
|
let text_buffers = &mut buffer_query;
|
||||||
#[cfg(feature = "bevy_text")]
|
|
||||||
let font_system = text_pipeline.font_system_mut();
|
|
||||||
// clean up removed nodes after syncing children to avoid potential panic (invalid SlotMap key used)
|
// clean up removed nodes after syncing children to avoid potential panic (invalid SlotMap key used)
|
||||||
ui_surface.remove_entities(removed_components.removed_nodes.read());
|
ui_surface.remove_entities(removed_components.removed_nodes.read());
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ pub fn ui_layout_system(
|
|||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
text_buffers,
|
text_buffers,
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
font_system,
|
&mut font_system.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
for root in &camera.root_nodes {
|
for root in &camera.root_nodes {
|
||||||
@ -523,6 +523,10 @@ mod tests {
|
|||||||
world.init_resource::<ManualTextureViews>();
|
world.init_resource::<ManualTextureViews>();
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
world.init_resource::<bevy_text::TextPipeline>();
|
world.init_resource::<bevy_text::TextPipeline>();
|
||||||
|
#[cfg(feature = "bevy_text")]
|
||||||
|
world.init_resource::<bevy_text::CosmicFontSystem>();
|
||||||
|
#[cfg(feature = "bevy_text")]
|
||||||
|
world.init_resource::<bevy_text::SwashCache>();
|
||||||
|
|
||||||
// spawn a dummy primary window and camera
|
// spawn a dummy primary window and camera
|
||||||
world.spawn((
|
world.spawn((
|
||||||
@ -1160,6 +1164,10 @@ mod tests {
|
|||||||
world.init_resource::<ManualTextureViews>();
|
world.init_resource::<ManualTextureViews>();
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
world.init_resource::<bevy_text::TextPipeline>();
|
world.init_resource::<bevy_text::TextPipeline>();
|
||||||
|
#[cfg(feature = "bevy_text")]
|
||||||
|
world.init_resource::<bevy_text::CosmicFontSystem>();
|
||||||
|
#[cfg(feature = "bevy_text")]
|
||||||
|
world.init_resource::<bevy_text::SwashCache>();
|
||||||
|
|
||||||
// spawn a dummy primary window and camera
|
// spawn a dummy primary window and camera
|
||||||
world.spawn((
|
world.spawn((
|
||||||
|
|||||||
@ -16,8 +16,9 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
|||||||
use bevy_render::{camera::Camera, texture::Image};
|
use bevy_render::{camera::Camera, texture::Image};
|
||||||
use bevy_sprite::TextureAtlasLayout;
|
use bevy_sprite::TextureAtlasLayout;
|
||||||
use bevy_text::{
|
use bevy_text::{
|
||||||
scale_value, BreakLineOn, CosmicBuffer, Font, FontAtlasSets, JustifyText, Text, TextBounds,
|
scale_value, BreakLineOn, CosmicBuffer, CosmicFontSystem, Font, FontAtlasSets, JustifyText,
|
||||||
TextError, TextLayoutInfo, TextMeasureInfo, TextPipeline, YAxisOrientation,
|
SwashCache, Text, TextBounds, TextError, TextLayoutInfo, TextMeasureInfo, TextPipeline,
|
||||||
|
YAxisOrientation,
|
||||||
};
|
};
|
||||||
use bevy_utils::{tracing::error, Entry};
|
use bevy_utils::{tracing::error, Entry};
|
||||||
use taffy::style::AvailableSpace;
|
use taffy::style::AvailableSpace;
|
||||||
@ -112,6 +113,7 @@ fn create_text_measure(
|
|||||||
mut text_flags: Mut<TextFlags>,
|
mut text_flags: Mut<TextFlags>,
|
||||||
buffer: &mut CosmicBuffer,
|
buffer: &mut CosmicBuffer,
|
||||||
text_alignment: JustifyText,
|
text_alignment: JustifyText,
|
||||||
|
font_system: &mut CosmicFontSystem,
|
||||||
) {
|
) {
|
||||||
match text_pipeline.create_text_measure(
|
match text_pipeline.create_text_measure(
|
||||||
entity,
|
entity,
|
||||||
@ -121,6 +123,7 @@ fn create_text_measure(
|
|||||||
text.linebreak_behavior,
|
text.linebreak_behavior,
|
||||||
buffer,
|
buffer,
|
||||||
text_alignment,
|
text_alignment,
|
||||||
|
font_system,
|
||||||
) {
|
) {
|
||||||
Ok(measure) => {
|
Ok(measure) => {
|
||||||
if text.linebreak_behavior == BreakLineOn::NoWrap {
|
if text.linebreak_behavior == BreakLineOn::NoWrap {
|
||||||
@ -173,6 +176,7 @@ pub fn measure_text_system(
|
|||||||
With<Node>,
|
With<Node>,
|
||||||
>,
|
>,
|
||||||
mut text_pipeline: ResMut<TextPipeline>,
|
mut text_pipeline: ResMut<TextPipeline>,
|
||||||
|
mut font_system: ResMut<CosmicFontSystem>,
|
||||||
) {
|
) {
|
||||||
scale_factors_buffer.clear();
|
scale_factors_buffer.clear();
|
||||||
|
|
||||||
@ -208,6 +212,7 @@ pub fn measure_text_system(
|
|||||||
text_flags,
|
text_flags,
|
||||||
buffer.as_mut(),
|
buffer.as_mut(),
|
||||||
text_alignment,
|
text_alignment,
|
||||||
|
&mut font_system,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,6 +234,8 @@ fn queue_text(
|
|||||||
mut text_flags: Mut<TextFlags>,
|
mut text_flags: Mut<TextFlags>,
|
||||||
text_layout_info: Mut<TextLayoutInfo>,
|
text_layout_info: Mut<TextLayoutInfo>,
|
||||||
buffer: &mut CosmicBuffer,
|
buffer: &mut CosmicBuffer,
|
||||||
|
font_system: &mut CosmicFontSystem,
|
||||||
|
swash_cache: &mut SwashCache,
|
||||||
) {
|
) {
|
||||||
// Skip the text node if it is waiting for a new measure func
|
// Skip the text node if it is waiting for a new measure func
|
||||||
if !text_flags.needs_new_measure_func {
|
if !text_flags.needs_new_measure_func {
|
||||||
@ -258,6 +265,8 @@ fn queue_text(
|
|||||||
textures,
|
textures,
|
||||||
YAxisOrientation::TopToBottom,
|
YAxisOrientation::TopToBottom,
|
||||||
buffer,
|
buffer,
|
||||||
|
font_system,
|
||||||
|
swash_cache,
|
||||||
) {
|
) {
|
||||||
Err(TextError::NoSuchFont) => {
|
Err(TextError::NoSuchFont) => {
|
||||||
// There was an error processing the text layout, try again next frame
|
// There was an error processing the text layout, try again next frame
|
||||||
@ -305,6 +314,8 @@ pub fn text_system(
|
|||||||
Option<&TargetCamera>,
|
Option<&TargetCamera>,
|
||||||
&mut CosmicBuffer,
|
&mut CosmicBuffer,
|
||||||
)>,
|
)>,
|
||||||
|
mut font_system: ResMut<CosmicFontSystem>,
|
||||||
|
mut swash_cache: ResMut<SwashCache>,
|
||||||
) {
|
) {
|
||||||
scale_factors_buffer.clear();
|
scale_factors_buffer.clear();
|
||||||
|
|
||||||
@ -343,6 +354,8 @@ pub fn text_system(
|
|||||||
text_flags,
|
text_flags,
|
||||||
text_layout_info,
|
text_layout_info,
|
||||||
buffer.as_mut(),
|
buffer.as_mut(),
|
||||||
|
&mut font_system,
|
||||||
|
&mut swash_cache,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user