diff --git a/crates/bevy_text/src/pipeline.rs b/crates/bevy_text/src/pipeline.rs index 093ef8ed3c3bf..f0b66275ed523 100644 --- a/crates/bevy_text/src/pipeline.rs +++ b/crates/bevy_text/src/pipeline.rs @@ -9,7 +9,6 @@ use bevy_image::prelude::*; use bevy_log::{once, warn}; use bevy_math::{Rect, UVec2, Vec2}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use smol_str::SmolStr; use crate::{ add_glyph_to_atlas, error::TextError, get_glyph_atlas_info, ComputedTextBlock, Font, @@ -49,28 +48,15 @@ impl Default for SwashCache { } } -/// Information about a font collected as part of preparing for text layout. -#[derive(Clone)] -pub struct FontFaceInfo { - /// Font family name - pub family_name: SmolStr, -} - /// The `TextPipeline` is used to layout and render text blocks (see `Text`/`Text2d`). /// /// See the [crate-level documentation](crate) for more information. #[derive(Default, Resource)] pub struct TextPipeline { - /// Buffered vec for collecting spans. + /// Buffered vec for collecting text sections. /// /// See [this dark magic](https://users.rust-lang.org/t/how-to-cache-a-vectors-capacity/94478/10). - spans_buffer: Vec<( - usize, - &'static str, - &'static TextFont, - FontFaceInfo, - LineHeight, - )>, + sections_buffer: Vec<(&'static str, Attrs<'static>)>, } impl TextPipeline { @@ -102,43 +88,32 @@ impl TextPipeline { let font_system = &mut font_system.0; - // Collect span information into a vec. This is necessary because font loading requires mut access + // Collect section information into a vec. This is necessary because font loading requires mut access // to FontSystem, which the cosmic-text Buffer also needs. - let mut spans: Vec<(usize, &str, &TextFont, FontFaceInfo, Color, LineHeight)> = - core::mem::take(&mut self.spans_buffer) - .into_iter() - .map( - |_| -> (usize, &str, &TextFont, FontFaceInfo, Color, LineHeight) { - unreachable!() - }, - ) - .collect(); + let mut sections: Vec<(&str, Attrs)> = core::mem::take(&mut self.sections_buffer) + .into_iter() + .map(|_| -> (&str, Attrs) { unreachable!() }) + .collect(); let result = { - for (span_index, (entity, depth, span, text_font, color, line_height)) in + for (span_index, (entity, depth, span, text_font, _color, line_height)) in text_spans.enumerate() { - // Save this span entity in the computed text block. + // Save this section entity in the computed text block. computed.entities.push(TextEntity { entity, depth }); if span.is_empty() { continue; } - let family_name: SmolStr = match &text_font.font { + let family: Family = match &text_font.font { FontSource::Handle(handle) => { - // Return early if a font is not loaded yet. - fonts - .get(handle.id()) - .ok_or(TextError::NoSuchFont)? - .family_name - .clone() + let font = fonts.get(handle.id()).ok_or(TextError::NoSuchFont)?; + Family::Name(font.family_name.as_str()) } - FontSource::Family(family) => family.clone(), + FontSource::Family(family) => Family::Name(family.as_str()), }; - let face_info = FontFaceInfo { family_name }; - // Save spans that aren't zero-sized. if text_font.font_size <= 0.0 { once!(warn!( @@ -147,38 +122,19 @@ impl TextPipeline { continue; } - spans.push((span_index, span, text_font, face_info, color, line_height)); - } - // Map text sections to cosmic-text spans, and ignore sections with negative or zero fontsizes, - // since they cannot be rendered by cosmic-text. - // - // 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, line_height)| { - ( - *span, - get_attrs( - *span_index, - text_font, - *line_height, - *color, - font_info, - scale_factor, - ), - ) - }, - ); + let attrs = get_attrs(span_index, text_font, line_height, family, scale_factor); + + sections.push((span, attrs)); + } - // Update the buffer. - let buffer = &mut computed.buffer; + // Update the Cosmic Text buffer. + let cosmic_buffer = &mut computed.buffer; // Set the metrics hinting strategy - buffer.set_hinting(font_system, hinting.into()); + cosmic_buffer.set_hinting(font_system, hinting.into()); - buffer.set_wrap( + cosmic_buffer.set_wrap( font_system, match linebreak { LineBreak::WordBoundary => Wrap::Word, @@ -188,9 +144,9 @@ impl TextPipeline { }, ); - buffer.set_rich_text( + cosmic_buffer.set_rich_text( font_system, - spans_iter, + sections.drain(..), &Attrs::new(), Shaping::Advanced, Some(justify.into()), @@ -199,25 +155,17 @@ impl TextPipeline { // Workaround for alignment not working for unbounded text. // See https://github.com/pop-os/cosmic-text/issues/343 let width = (bounds.width.is_none() && justify != Justify::Left) - .then(|| buffer_dimensions(buffer).x) + .then(|| buffer_dimensions(cosmic_buffer).x) .or(bounds.width); - buffer.set_size(font_system, width, bounds.height); + cosmic_buffer.set_size(font_system, width, bounds.height); Ok(()) }; - // Recover the spans buffer. - spans.clear(); - self.spans_buffer = spans + // Recover the sections buffer. + sections.clear(); + self.sections_buffer = sections .into_iter() - .map( - |_| -> ( - usize, - &'static str, - &'static TextFont, - FontFaceInfo, - LineHeight, - ) { unreachable!() }, - ) + .map(|_| -> (&'static str, Attrs<'static>) { unreachable!() }) .collect(); result @@ -537,13 +485,12 @@ fn get_attrs<'a>( span_index: usize, text_font: &TextFont, line_height: LineHeight, - color: Color, - face_info: &'a FontFaceInfo, + family: Family<'a>, scale_factor: f64, ) -> Attrs<'a> { Attrs::new() .metadata(span_index) - .family(Family::Name(&face_info.family_name)) + .family(family) .stretch(text_font.width.into()) .style(text_font.style.into()) .weight(text_font.weight.into()) @@ -555,7 +502,6 @@ fn get_attrs<'a>( .scale(scale_factor as f32), ) .font_features((&text_font.font_features).into()) - .color(cosmic_text::Color(color.to_linear().as_u32())) } /// Calculate the size of the text area for the given buffer.