Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions crates/bevy_feathers/src/font_styles.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! A framework for inheritable font styles.
use bevy_app::{Propagate, PropagateOver};
use bevy_asset::{AssetServer, Handle};
use bevy_ecs::{
component::Component,
Expand All @@ -17,7 +16,7 @@ use crate::{handle_or_path::HandleOrPath, theme::ThemedText};
/// downward to any child text entity that has the [`ThemedText`] marker.
#[derive(Component, Default, Clone, Debug, Reflect)]
#[reflect(Component, Default)]
#[require(ThemedText, PropagateOver::<TextFont>::default())]
#[require(ThemedText)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even need ThemedText any more?

Copy link
Contributor Author

@ickshonpe ickshonpe Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like it, I thought I'd leave it for now though, and focus this PR on the text module changes.

pub struct InheritableFont {
/// The font handle or path.
pub font: HandleOrPath<Font>,
Expand Down Expand Up @@ -57,10 +56,10 @@ pub(crate) fn on_changed_font(
HandleOrPath::Path(ref p) => Some(assets.load::<Font>(p)),
}
{
commands.entity(insert.entity).insert(Propagate(TextFont {
commands.entity(insert.entity).insert(TextFont {
font,
font_size: style.font_size,
..Default::default()
}));
});
}
}
18 changes: 2 additions & 16 deletions crates/bevy_feathers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,17 @@
//! Please report issues, submit fixes and propose changes.
//! Thanks for stress-testing; let's build something better together.

use bevy_app::{
HierarchyPropagatePlugin, Plugin, PluginGroup, PluginGroupBuilder, PostUpdate, PropagateSet,
};
use bevy_app::{Plugin, PluginGroup, PluginGroupBuilder, PostUpdate};
use bevy_asset::embedded_asset;
use bevy_ecs::{query::With, schedule::IntoScheduleConfigs};
use bevy_input_focus::{tab_navigation::TabNavigationPlugin, InputDispatchPlugin};
use bevy_text::{TextColor, TextFont};
use bevy_ui::UiSystems;
use bevy_ui_render::UiMaterialPlugin;
use bevy_ui_widgets::UiWidgetsPlugins;

use crate::{
alpha_pattern::{AlphaPatternMaterial, AlphaPatternResource},
controls::ControlsPlugin,
cursor::{CursorIconPlugin, DefaultCursor, EntityCursor},
theme::{ThemedText, UiTheme},
theme::UiTheme,
};

mod alpha_pattern;
Expand Down Expand Up @@ -68,18 +63,9 @@ impl Plugin for FeathersPlugin {
app.add_plugins((
ControlsPlugin,
CursorIconPlugin,
HierarchyPropagatePlugin::<TextColor, With<ThemedText>>::new(PostUpdate),
HierarchyPropagatePlugin::<TextFont, With<ThemedText>>::new(PostUpdate),
UiMaterialPlugin::<AlphaPatternMaterial>::default(),
));

// This needs to run in UiSystems::Propagate so the fonts are up-to-date for `measure_text_system`
// and `detect_text_needs_rerender` in UiSystems::Content
app.configure_sets(
PostUpdate,
PropagateSet::<TextFont>::default().in_set(UiSystems::Propagate),
);

app.insert_resource(DefaultCursor(EntityCursor::System(
bevy_window::SystemCursorIcon::Default,
)));
Expand Down
7 changes: 2 additions & 5 deletions crates/bevy_feathers/src/theme.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! A framework for theming.
use bevy_app::{Propagate, PropagateOver};
use bevy_color::{palettes, Color};
use bevy_ecs::{
change_detection::DetectChanges,
Expand Down Expand Up @@ -105,7 +104,7 @@ pub struct ThemeBorderColor(pub ThemeToken);
#[component(immutable)]
#[derive(Reflect)]
#[reflect(Component, Clone)]
#[require(ThemedText, PropagateOver::<TextColor>::default())]
#[require(ThemedText)]
pub struct ThemeFontColor(pub ThemeToken);

/// A marker component that is used to indicate that the text entity wants to opt-in to using
Expand Down Expand Up @@ -167,8 +166,6 @@ pub(crate) fn on_changed_font_color(
) {
if let Ok(token) = font_color.get(insert.entity) {
let color = theme.color(&token.0);
commands
.entity(insert.entity)
.insert(Propagate(TextColor(color)));
commands.entity(insert.entity).insert(TextColor(color));
}
}
3 changes: 3 additions & 0 deletions crates/bevy_sprite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ use bevy_camera::{
visibility::VisibilitySystems,
};
use bevy_mesh::{Mesh, Mesh2d};
#[cfg(feature = "bevy_text")]
use bevy_text::update_text_styles;
#[cfg(feature = "bevy_sprite_picking_backend")]
pub use picking_backend::*;
pub use sprite::*;
Expand Down Expand Up @@ -87,6 +89,7 @@ impl Plugin for SpritePlugin {
bevy_text::detect_text_needs_rerender::<Text2d>,
update_text2d_layout
.after(bevy_camera::CameraUpdateSystems)
.after(update_text_styles)
.after(bevy_text::remove_dropped_font_atlas_sets),
calculate_bounds_text2d.in_set(VisibilitySystems::CalculateBounds),
)
Expand Down
14 changes: 9 additions & 5 deletions crates/bevy_sprite/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ use bevy_ecs::{
use bevy_image::prelude::*;
use bevy_math::{FloatOrd, Vec2, Vec3};
use bevy_reflect::{prelude::ReflectDefault, Reflect};
use bevy_text::ComputedTextStyle;
use bevy_text::{
ComputedTextBlock, CosmicFontSystem, Font, FontAtlasSets, LineBreak, SwashCache, TextBounds,
TextColor, TextError, TextFont, TextLayout, TextLayoutInfo, TextPipeline, TextReader, TextRoot,
TextSpanAccess, TextWriter,
TextError, TextLayout, TextLayoutInfo, TextPipeline, TextReader, TextRoot, TextSpanAccess,
TextWriter,
};
use bevy_transform::components::Transform;
use core::any::TypeId;
Expand Down Expand Up @@ -81,12 +82,11 @@ use core::any::TypeId;
#[reflect(Component, Default, Debug, Clone)]
#[require(
TextLayout,
TextFont,
TextColor,
TextBounds,
Anchor,
Visibility,
VisibilityClass,
ComputedTextStyle,
Transform
)]
#[component(on_add = visibility::add_visibility_class::<Sprite>)]
Expand Down Expand Up @@ -309,7 +309,9 @@ mod tests {
use bevy_camera::{ComputedCameraValues, RenderTargetInfo};
use bevy_ecs::schedule::IntoScheduleConfigs;
use bevy_math::UVec2;
use bevy_text::{detect_text_needs_rerender, TextIterScratch};
use bevy_text::{
detect_text_needs_rerender, update_text_styles, DefaultTextStyle, TextIterScratch,
};

use super::*;

Expand All @@ -326,9 +328,11 @@ mod tests {
.init_resource::<CosmicFontSystem>()
.init_resource::<SwashCache>()
.init_resource::<TextIterScratch>()
.init_resource::<DefaultTextStyle>()
.add_systems(
Update,
(
update_text_styles,
detect_text_needs_rerender::<Text2d>,
update_text2d_layout,
calculate_bounds_text2d,
Expand Down
7 changes: 4 additions & 3 deletions crates/bevy_sprite_render/src/text2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use bevy_render::sync_world::TemporaryRenderEntity;
use bevy_render::Extract;
use bevy_sprite::{Anchor, Text2dShadow};
use bevy_text::{
ComputedTextBlock, PositionedGlyph, TextBackgroundColor, TextBounds, TextColor, TextLayoutInfo,
ComputedTextBlock, ComputedTextStyle, PositionedGlyph, TextBackgroundColor, TextBounds,
TextLayoutInfo,
};
use bevy_transform::prelude::GlobalTransform;

Expand All @@ -37,7 +38,7 @@ pub fn extract_text2d_sprite(
&GlobalTransform,
)>,
>,
text_colors: Extract<Query<&TextColor>>,
text_colors: Extract<Query<&ComputedTextStyle>>,
text_background_colors_query: Extract<Query<&TextBackgroundColor>>,
) {
let mut start = extracted_slices.slices.len();
Expand Down Expand Up @@ -170,7 +171,7 @@ pub fn extract_text2d_sprite(
.map(|t| t.entity)
.unwrap_or(Entity::PLACEHOLDER),
)
.map(|text_color| LinearRgba::from(text_color.0))
.map(|style| LinearRgba::from(style.color()))
.unwrap_or_default();
current_span = *span_index;
}
Expand Down
11 changes: 9 additions & 2 deletions crates/bevy_text/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod font_atlas_set;
mod font_loader;
mod glyph;
mod pipeline;
mod style;
mod text;
mod text_access;

Expand All @@ -50,6 +51,7 @@ pub use font_atlas_set::*;
pub use font_loader::*;
pub use glyph::*;
pub use pipeline::*;
pub use style::*;
pub use text::*;
pub use text_access::*;

Expand All @@ -59,7 +61,8 @@ pub use text_access::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
Font, Justify, LineBreak, TextColor, TextError, TextFont, TextLayout, TextSpan,
ComputedTextStyle, Font, Justify, LineBreak, TextColor, TextError, TextFont, TextLayout,
TextSpan,
};
}

Expand Down Expand Up @@ -95,9 +98,13 @@ impl Plugin for TextPlugin {
.init_resource::<CosmicFontSystem>()
.init_resource::<SwashCache>()
.init_resource::<TextIterScratch>()
.init_resource::<DefaultTextStyle>()
.add_systems(
PostUpdate,
remove_dropped_font_atlas_sets.before(AssetEventSystems),
(
update_text_styles,
remove_dropped_font_atlas_sets.before(AssetEventSystems),
),
)
.add_systems(Last, trim_cosmic_cache);

Expand Down
58 changes: 28 additions & 30 deletions crates/bevy_text/src/pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use alloc::sync::Arc;

use bevy_asset::{AssetId, Assets};
use bevy_color::Color;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
component::Component, entity::Entity, reflect::ReflectComponent, resource::Resource,
Expand All @@ -16,8 +15,9 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use cosmic_text::{Attrs, Buffer, Family, Metrics, Shaping, Wrap};

use crate::{
error::TextError, ComputedTextBlock, Font, FontAtlasSets, FontSmoothing, Justify, LineBreak,
PositionedGlyph, TextBounds, TextEntity, TextFont, TextLayout,
error::TextError, style::ComputedTextStyle, ComputedTextBlock, Font, FontAtlasSets,
FontSmoothing, Justify, LineBreak, PositionedGlyph, TextBounds, TextEntity, TextFont,
TextLayout,
};

/// A wrapper resource around a [`cosmic_text::FontSystem`]
Expand Down Expand Up @@ -86,7 +86,7 @@ impl TextPipeline {
pub fn update_buffer<'a>(
&mut self,
fonts: &Assets<Font>,
text_spans: impl Iterator<Item = (Entity, usize, &'a str, &'a TextFont, Color)>,
text_spans: impl Iterator<Item = (Entity, usize, &'a str, &'a ComputedTextStyle)>,
linebreak: LineBreak,
justify: Justify,
bounds: TextBounds,
Expand All @@ -100,23 +100,23 @@ impl TextPipeline {
// to FontSystem, which the cosmic-text Buffer also needs.
let mut max_font_size: f32 = 0.;
let mut max_line_height: f32 = 0.0;
let mut spans: Vec<(usize, &str, &TextFont, FontFaceInfo, Color)> =
let mut spans: Vec<(usize, &str, &ComputedTextStyle, FontFaceInfo)> =
core::mem::take(&mut self.spans_buffer)
.into_iter()
.map(|_| -> (usize, &str, &TextFont, FontFaceInfo, Color) { unreachable!() })
.map(|_| -> (usize, &str, &ComputedTextStyle, FontFaceInfo) { unreachable!() })
.collect();

computed.entities.clear();

for (span_index, (entity, depth, span, text_font, color)) in text_spans.enumerate() {
for (span_index, (entity, depth, span, style)) in text_spans.enumerate() {
// Save this span entity in the computed text block.
computed.entities.push(TextEntity { entity, depth });

if span.is_empty() {
continue;
}
// Return early if a font is not loaded yet.
if !fonts.contains(text_font.font.id()) {
if !fonts.contains(style.font.font.id()) {
spans.clear();
self.spans_buffer = spans
.into_iter()
Expand All @@ -131,26 +131,27 @@ impl TextPipeline {
}

// Get max font size for use in cosmic Metrics.
max_font_size = max_font_size.max(text_font.font_size);
max_line_height = max_line_height.max(text_font.line_height.eval(text_font.font_size));
max_font_size = max_font_size.max(style.font.font_size);
max_line_height =
max_line_height.max(style.font.line_height.eval(style.font.font_size));

// Load Bevy fonts into cosmic-text's font system.
let face_info = load_font_to_fontdb(
text_font,
&style.font,
font_system,
&mut self.map_handle_to_font_id,
fonts,
);

// Save spans that aren't zero-sized.
if scale_factor <= 0.0 || text_font.font_size <= 0.0 {
if scale_factor <= 0.0 || style.font.font_size <= 0.0 {
once!(warn!(
"Text span {entity} has a font size <= 0.0. Nothing will be displayed.",
));

continue;
}
spans.push((span_index, span, text_font, face_info, color));
spans.push((span_index, span, style, face_info));
}

let mut metrics = Metrics::new(max_font_size, max_line_height).scale(scale_factor as f32);
Expand All @@ -166,14 +167,12 @@ impl TextPipeline {
// The section index is stored in the metadata of the spans, and could be used
// to look up the section the span came from and is not used internally
// in cosmic-text.
let spans_iter = spans
.iter()
.map(|(span_index, span, text_font, font_info, color)| {
(
*span,
get_attrs(*span_index, text_font, *color, font_info, scale_factor),
)
});
let spans_iter = spans.iter().map(|(span_index, span, style, font_info)| {
(
*span,
get_attrs(*span_index, style, font_info, scale_factor),
)
});

// Update the buffer.
let buffer = &mut computed.buffer;
Expand Down Expand Up @@ -225,7 +224,7 @@ impl TextPipeline {
&mut self,
layout_info: &mut TextLayoutInfo,
fonts: &Assets<Font>,
text_spans: impl Iterator<Item = (Entity, usize, &'a str, &'a TextFont, Color)>,
text_spans: impl Iterator<Item = (Entity, usize, &'a str, &'a ComputedTextStyle)>,
scale_factor: f64,
layout: &TextLayout,
bounds: TextBounds,
Expand All @@ -246,8 +245,8 @@ impl TextPipeline {
// Extract font ids from the iterator while traversing it.
let mut glyph_info = core::mem::take(&mut self.glyph_info);
glyph_info.clear();
let text_spans = text_spans.inspect(|(_, _, _, text_font, _)| {
glyph_info.push((text_font.font.id(), text_font.font_smoothing));
let text_spans = text_spans.inspect(|(_, _, _, text_style)| {
glyph_info.push((text_style.font.font.id(), text_style.font.font_smoothing));
});

let update_result = self.update_buffer(
Expand Down Expand Up @@ -394,7 +393,7 @@ impl TextPipeline {
&mut self,
entity: Entity,
fonts: &Assets<Font>,
text_spans: impl Iterator<Item = (Entity, usize, &'a str, &'a TextFont, Color)>,
text_spans: impl Iterator<Item = (Entity, usize, &'a str, &'a ComputedTextStyle)>,
scale_factor: f64,
layout: &TextLayout,
computed: &mut ComputedTextBlock,
Expand Down Expand Up @@ -529,8 +528,7 @@ pub fn load_font_to_fontdb(
/// Translates [`TextFont`] to [`Attrs`].
fn get_attrs<'a>(
span_index: usize,
text_font: &TextFont,
color: Color,
style: &'a ComputedTextStyle,
face_info: &'a FontFaceInfo,
scale_factor: f64,
) -> Attrs<'a> {
Expand All @@ -542,12 +540,12 @@ fn get_attrs<'a>(
.weight(face_info.weight)
.metrics(
Metrics {
font_size: text_font.font_size,
line_height: text_font.line_height.eval(text_font.font_size),
font_size: style.font.font_size,
line_height: style.font.line_height.eval(style.font.font_size),
}
.scale(scale_factor as f32),
)
.color(cosmic_text::Color(color.to_linear().as_u32()))
.color(cosmic_text::Color(style.color.to_linear().as_u32()))
}

/// Calculate the size of the text area for the given buffer.
Expand Down
Loading
Loading