diff --git a/crates/epaint/src/text/fonts.rs b/crates/epaint/src/text/fonts.rs index 839ac97c5..f92c5c103 100644 --- a/crates/epaint/src/text/fonts.rs +++ b/crates/epaint/src/text/fonts.rs @@ -813,6 +813,7 @@ impl GalleyCache { ) -> Galley { profiling::function_scope!(); + let mut current_section = 0; let mut start = 0; let mut max_rows_remaining = job.wrap.max_rows; let mut galleys = Vec::new(); @@ -841,36 +842,49 @@ impl GalleyCache { round_output_to_gui: job.round_output_to_gui, }; - // Keep all (previous) sections (so the correct `section_index` is outputted), - // but shift their byte ranges: - paragraph_job.sections = job - .sections - .iter() - .cloned() - .filter_map(|section| { - let LayoutSection { - leading_space, - byte_range, - format, - } = section; - if end <= byte_range.start { - None - } else { - let byte_range = byte_range.start.saturating_sub(start) - ..byte_range.end.saturating_sub(start).min(end - start); - Some(LayoutSection { - leading_space: if byte_range.end == 0 { - 0.0 // this section is behind us (unused in this paragraph) - } else { - leading_space - }, - byte_range, - format, - }) - } - }) - .collect(); + // Add overlapping sections: + for section in &job.sections[current_section..job.sections.len()] { + let LayoutSection { + leading_space, + byte_range: section_range, + format, + } = section; + // dbg!(section_index, section_range); + + // `start` and `end` are the byte range of the current paragraph. + // How does the current section overlap with the paragraph range? + + if section_range.end <= start { + // The section is behind us + current_section += 1; + } else if end <= section_range.start { + break; // Haven't reached this one yet. + } else { + // Section range overlaps with paragraph range + debug_assert!( + section_range.start < section_range.end, + "Bad byte_range: {section_range:?}" + ); + let new_range = section_range.start.saturating_sub(start) + ..(section_range.end.at_most(end)).saturating_sub(start); + debug_assert!( + new_range.start <= new_range.end, + "Bad new section range: {new_range:?}" + ); + paragraph_job.sections.push(LayoutSection { + leading_space: if start <= new_range.start { + *leading_space + } else { + 0.0 + }, + byte_range: new_range, + format: format.clone(), + }); + } + } + + // TODO(emilk): we could lay out each paragraph in parallel to get a nice speedup on multicore machines. let galley = self.layout(fonts, paragraph_job, false); // This will prevent us from invalidating cache entries unnecessarily: @@ -891,6 +905,7 @@ impl GalleyCache { start = end; } + // TODO: adjust section_index in the concatted galley Galley::concat(job, &galleys, fonts.pixels_per_point) } diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs index e41074774..26bf6860c 100644 --- a/crates/epaint/src/text/text_layout.rs +++ b/crates/epaint/src/text/text_layout.rs @@ -69,6 +69,8 @@ impl Paragraph { /// In most cases you should use [`crate::Fonts::layout_job`] instead /// since that memoizes the input, making subsequent layouting of the same text much faster. pub fn layout(fonts: &mut FontsImpl, job: Arc) -> Galley { + profiling::function_scope!(); + if job.wrap.max_rows == 0 { // Early-out: no text return Galley { diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index 0e59a215b..4e38e7e64 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -792,6 +792,8 @@ impl Galley { /// Append each galley under the previous one. pub fn concat(job: Arc, galleys: &[Arc], pixels_per_point: f32) -> Self { + profiling::function_scope!(); + let mut merged_galley = Self { job, rows: Vec::new(),