mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-27 02:48:34 +00:00
Checkpoint
This commit is contained in:
parent
847376cd8f
commit
938dd8b9ca
7 changed files with 130 additions and 116 deletions
|
@ -155,8 +155,9 @@ impl Refineable for TextStyleRefinement {
|
|||
}
|
||||
}
|
||||
|
||||
fn refined(self, refinement: Self::Refinement) -> Self {
|
||||
todo!()
|
||||
fn refined(mut self, refinement: Self::Refinement) -> Self {
|
||||
self.refine(&refinement);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
|
||||
size, AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smallvec::SmallVec;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use util::{arc_cow::ArcCow, ResultExt};
|
||||
|
||||
|
@ -75,7 +76,7 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
|
|||
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
||||
let element_state = element_state.clone();
|
||||
move |known_dimensions, _| {
|
||||
let Some(line_layout) = text_system
|
||||
let Some(lines) = text_system
|
||||
.layout_text(
|
||||
text.as_ref(),
|
||||
font_size,
|
||||
|
@ -88,14 +89,13 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
|
|||
};
|
||||
|
||||
let size = Size {
|
||||
width: line_layout.width(),
|
||||
height: line_height,
|
||||
width: lines.iter().map(|line| line.width()).max().unwrap(),
|
||||
height: line_height * lines.len(),
|
||||
};
|
||||
|
||||
element_state.lock().replace(TextElementState {
|
||||
line: Arc::new(line_layout),
|
||||
line_height,
|
||||
});
|
||||
element_state
|
||||
.lock()
|
||||
.replace(TextElementState { lines, line_height });
|
||||
|
||||
size
|
||||
}
|
||||
|
@ -111,22 +111,25 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
|
|||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<S>,
|
||||
) {
|
||||
let line;
|
||||
let line_height;
|
||||
{
|
||||
let element_state = element_state.lock();
|
||||
let element_state = element_state
|
||||
.as_ref()
|
||||
.expect("measurement has not been performed");
|
||||
line = element_state.line.clone();
|
||||
line_height = element_state.line_height;
|
||||
let element_state = element_state.lock();
|
||||
let element_state = element_state
|
||||
.as_ref()
|
||||
.expect("measurement has not been performed");
|
||||
let line_height = element_state.line_height;
|
||||
let mut line_origin = bounds.origin;
|
||||
for line in &element_state.lines {
|
||||
let line_bounds = Bounds {
|
||||
origin: line_origin,
|
||||
size: size(line.width(), line_height),
|
||||
};
|
||||
line.paint(line_bounds, line_bounds, line_height, cx)
|
||||
.log_err();
|
||||
line_origin.y += line_height;
|
||||
}
|
||||
|
||||
line.paint(bounds, bounds, line_height, cx).log_err();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextElementState {
|
||||
line: Arc<Line>,
|
||||
lines: SmallVec<[Arc<Line>; 1]>,
|
||||
line_height: Pixels,
|
||||
}
|
||||
|
|
|
@ -656,6 +656,14 @@ impl Mul<f32> for Pixels {
|
|||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Pixels {
|
||||
type Output = Pixels;
|
||||
|
||||
fn mul(self, other: usize) -> Pixels {
|
||||
Pixels(self.0 * other as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Pixels> for f32 {
|
||||
type Output = Pixels;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use collections::HashMap;
|
|||
use core::fmt;
|
||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||
use std::{
|
||||
cmp,
|
||||
fmt::{Debug, Display, Formatter},
|
||||
hash::{Hash, Hasher},
|
||||
ops::{Deref, DerefMut},
|
||||
|
@ -150,63 +151,72 @@ impl TextSystem {
|
|||
font_size: Pixels,
|
||||
runs: &[(usize, RunStyle)],
|
||||
wrap_width: Option<Pixels>,
|
||||
) -> Result<SmallVec<[Line; 1]>> {
|
||||
) -> Result<SmallVec<[Arc<Line>; 1]>> {
|
||||
let mut runs = runs
|
||||
.iter()
|
||||
.map(|(run_len, style)| (*run_len, style))
|
||||
.peekable();
|
||||
let mut font_runs: Vec<(usize, FontId)> =
|
||||
self.font_runs_pool.lock().pop().unwrap_or_default();
|
||||
|
||||
let mut last_font: Option<&Font> = None;
|
||||
for (len, style) in runs {
|
||||
if let Some(last_font) = last_font.as_ref() {
|
||||
if **last_font == style.font {
|
||||
font_runs.last_mut().unwrap().0 += len;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
last_font = Some(&style.font);
|
||||
font_runs.push((*len, self.font_id(&style.font)?));
|
||||
}
|
||||
let mut lines = SmallVec::new();
|
||||
let mut line_start = 0;
|
||||
for line in text.split('\n') {
|
||||
let line_end = line_start + line.len();
|
||||
|
||||
let mut layouts = SmallVec::new();
|
||||
let mut start = 0;
|
||||
let mut run_start = 0;
|
||||
for line in text.lines() {
|
||||
let end = start + line.len();
|
||||
let mut run_end = run_start;
|
||||
let mut line_length = 0;
|
||||
for (len, _) in font_runs[run_start..].iter() {
|
||||
line_length += len;
|
||||
if *len >= line_length {
|
||||
let mut last_font: Option<&Font> = None;
|
||||
let mut decoration_runs = SmallVec::<[DecorationRun; 32]>::new();
|
||||
let mut run_start = line_start;
|
||||
while run_start < line_end {
|
||||
let Some((run_len, run_style)) = runs.peek_mut() else {
|
||||
break;
|
||||
};
|
||||
|
||||
let run_len_within_line = cmp::min(line_end, run_start + *run_len) - run_start;
|
||||
|
||||
if last_font == Some(&run_style.font) {
|
||||
font_runs.last_mut().unwrap().0 += run_len_within_line;
|
||||
} else {
|
||||
last_font = Some(&run_style.font);
|
||||
font_runs.push((
|
||||
run_len_within_line,
|
||||
self.platform_text_system.font_id(&run_style.font)?,
|
||||
));
|
||||
}
|
||||
run_end += 1;
|
||||
|
||||
if decoration_runs.last().map_or(false, |last_run| {
|
||||
last_run.color == run_style.color && last_run.underline == run_style.underline
|
||||
}) {
|
||||
decoration_runs.last_mut().unwrap().len += run_len_within_line as u32;
|
||||
} else {
|
||||
decoration_runs.push(DecorationRun {
|
||||
len: run_len_within_line as u32,
|
||||
color: run_style.color,
|
||||
underline: run_style.underline.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
if run_len_within_line == *run_len {
|
||||
runs.next();
|
||||
} else {
|
||||
// Preserve the remainder of the run for the next line
|
||||
*run_len -= run_len_within_line;
|
||||
}
|
||||
run_start += run_len_within_line;
|
||||
}
|
||||
// If a run lands in the middle of a line, create an additional run for the remaining characters.
|
||||
if line_length < end - start {
|
||||
// Create a run for the part that fits this line.
|
||||
let partial_run = font_runs[run_end];
|
||||
partial_run.0 = line_length;
|
||||
layouts.push(self.text_layout_cache.layout_line(
|
||||
&text[start..start + line_length],
|
||||
font_size,
|
||||
&font_runs[run_start..=run_end],
|
||||
));
|
||||
// Update the original run to only include the part that does not fit this line.
|
||||
font_runs[run_end].0 -= line_length;
|
||||
} else {
|
||||
layouts.push(self.text_layout_cache.layout_line(
|
||||
&text[start..end],
|
||||
font_size,
|
||||
&font_runs[run_start..run_end],
|
||||
));
|
||||
run_start = run_end;
|
||||
}
|
||||
start = end + 1;
|
||||
|
||||
let layout = self
|
||||
.text_layout_cache
|
||||
.layout_line(line, font_size, &font_runs);
|
||||
lines.push(Arc::new(Line::new(layout, decoration_runs)));
|
||||
|
||||
line_start = line_end + 1; // Skip `\n` character.
|
||||
font_runs.clear();
|
||||
}
|
||||
|
||||
font_runs.clear();
|
||||
self.font_runs_pool.lock().push(font_runs);
|
||||
|
||||
Ok(layouts)
|
||||
Ok(lines)
|
||||
}
|
||||
|
||||
pub fn end_frame(&self) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
black, point, px, Bounds, FontId, Hsla, LineLayout, Pixels, Point, RunStyle, ShapedBoundary,
|
||||
ShapedRun, UnderlineStyle, WindowContext,
|
||||
black, point, px, Bounds, FontId, Hsla, LineLayout, Pixels, Point, ShapedBoundary, ShapedRun,
|
||||
UnderlineStyle, WindowContext,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -9,27 +9,22 @@ use std::sync::Arc;
|
|||
#[derive(Default, Debug, Clone)]
|
||||
pub struct Line {
|
||||
layout: Arc<LineLayout>,
|
||||
style_runs: SmallVec<[StyleRun; 32]>,
|
||||
decoration_runs: SmallVec<[DecorationRun; 32]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct StyleRun {
|
||||
len: u32,
|
||||
color: Hsla,
|
||||
underline: UnderlineStyle,
|
||||
pub struct DecorationRun {
|
||||
pub len: u32,
|
||||
pub color: Hsla,
|
||||
pub underline: Option<UnderlineStyle>,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
pub fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
|
||||
let mut style_runs = SmallVec::new();
|
||||
for (len, style) in runs {
|
||||
style_runs.push(StyleRun {
|
||||
len: *len as u32,
|
||||
color: style.color,
|
||||
underline: style.underline.clone().unwrap_or_default(),
|
||||
});
|
||||
pub fn new(layout: Arc<LineLayout>, decoration_runs: SmallVec<[DecorationRun; 32]>) -> Self {
|
||||
Self {
|
||||
layout,
|
||||
decoration_runs,
|
||||
}
|
||||
Self { layout, style_runs }
|
||||
}
|
||||
|
||||
pub fn runs(&self) -> &[ShapedRun] {
|
||||
|
@ -101,10 +96,10 @@ impl Line {
|
|||
let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.;
|
||||
let baseline_offset = point(px(0.), padding_top + self.layout.ascent);
|
||||
|
||||
let mut style_runs = self.style_runs.iter();
|
||||
let mut style_runs = self.decoration_runs.iter();
|
||||
let mut run_end = 0;
|
||||
let mut color = black();
|
||||
let mut underline = None;
|
||||
let mut current_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
|
||||
let text_system = cx.text_system().clone();
|
||||
|
||||
for run in &self.layout.runs {
|
||||
|
@ -122,23 +117,21 @@ impl Line {
|
|||
let mut finished_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
|
||||
if glyph.index >= run_end {
|
||||
if let Some(style_run) = style_runs.next() {
|
||||
if let Some((_, underline_style)) = &mut underline {
|
||||
if style_run.underline != *underline_style {
|
||||
finished_underline = underline.take();
|
||||
if let Some((_, underline_style)) = &mut current_underline {
|
||||
if style_run.underline.as_ref() != Some(underline_style) {
|
||||
finished_underline = current_underline.take();
|
||||
}
|
||||
}
|
||||
if style_run.underline.thickness > px(0.) {
|
||||
underline.get_or_insert((
|
||||
if let Some(run_underline) = style_run.underline.as_ref() {
|
||||
current_underline.get_or_insert((
|
||||
point(
|
||||
glyph_origin.x,
|
||||
origin.y + baseline_offset.y + (self.layout.descent * 0.618),
|
||||
),
|
||||
UnderlineStyle {
|
||||
color: Some(
|
||||
style_run.underline.color.unwrap_or(style_run.color),
|
||||
),
|
||||
thickness: style_run.underline.thickness,
|
||||
wavy: style_run.underline.wavy,
|
||||
color: Some(run_underline.color.unwrap_or(style_run.color)),
|
||||
thickness: run_underline.thickness,
|
||||
wavy: run_underline.wavy,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
@ -147,7 +140,7 @@ impl Line {
|
|||
color = style_run.color;
|
||||
} else {
|
||||
run_end = self.layout.len;
|
||||
finished_underline = underline.take();
|
||||
finished_underline = current_underline.take();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +170,7 @@ impl Line {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((underline_start, underline_style)) = underline.take() {
|
||||
if let Some((underline_start, underline_style)) = current_underline.take() {
|
||||
let line_end_x = origin.x + self.layout.width;
|
||||
cx.paint_underline(
|
||||
underline_start,
|
||||
|
@ -201,10 +194,10 @@ impl Line {
|
|||
let baseline_offset = point(px(0.), padding_top + self.layout.ascent);
|
||||
|
||||
let mut boundaries = boundaries.into_iter().peekable();
|
||||
let mut color_runs = self.style_runs.iter();
|
||||
let mut color_runs = self.decoration_runs.iter();
|
||||
let mut style_run_end = 0;
|
||||
let mut _color = black(); // todo!
|
||||
let mut underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
|
||||
let mut current_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
|
||||
|
||||
let mut glyph_origin = origin;
|
||||
let mut prev_position = px(0.);
|
||||
|
@ -217,7 +210,7 @@ impl Line {
|
|||
.map_or(false, |b| b.run_ix == run_ix && b.glyph_ix == glyph_ix)
|
||||
{
|
||||
boundaries.next();
|
||||
if let Some((underline_origin, underline_style)) = underline.take() {
|
||||
if let Some((underline_origin, underline_style)) = current_underline.take() {
|
||||
cx.paint_underline(
|
||||
underline_origin,
|
||||
glyph_origin.x - underline_origin.x,
|
||||
|
@ -234,31 +227,29 @@ impl Line {
|
|||
if let Some(style_run) = color_runs.next() {
|
||||
style_run_end += style_run.len as usize;
|
||||
_color = style_run.color;
|
||||
if let Some((_, underline_style)) = &mut underline {
|
||||
if style_run.underline != *underline_style {
|
||||
finished_underline = underline.take();
|
||||
if let Some((_, underline_style)) = &mut current_underline {
|
||||
if style_run.underline.as_ref() != Some(underline_style) {
|
||||
finished_underline = current_underline.take();
|
||||
}
|
||||
}
|
||||
if style_run.underline.thickness > px(0.) {
|
||||
underline.get_or_insert((
|
||||
if let Some(underline_style) = style_run.underline.as_ref() {
|
||||
current_underline.get_or_insert((
|
||||
glyph_origin
|
||||
+ point(
|
||||
px(0.),
|
||||
baseline_offset.y + (self.layout.descent * 0.618),
|
||||
),
|
||||
UnderlineStyle {
|
||||
color: Some(
|
||||
style_run.underline.color.unwrap_or(style_run.color),
|
||||
),
|
||||
thickness: style_run.underline.thickness,
|
||||
wavy: style_run.underline.wavy,
|
||||
color: Some(underline_style.color.unwrap_or(style_run.color)),
|
||||
thickness: underline_style.thickness,
|
||||
wavy: underline_style.wavy,
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
style_run_end = self.layout.len;
|
||||
_color = black();
|
||||
finished_underline = underline.take();
|
||||
finished_underline = current_underline.take();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,7 +289,7 @@ impl Line {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((underline_origin, underline_style)) = underline.take() {
|
||||
if let Some((underline_origin, underline_style)) = current_underline.take() {
|
||||
let line_end_x = glyph_origin.x + self.layout.width - prev_position;
|
||||
cx.paint_underline(
|
||||
underline_origin,
|
||||
|
|
|
@ -286,7 +286,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let text = "aa bbb cccc ddddd eeee";
|
||||
let line = text_system
|
||||
let lines = text_system
|
||||
.layout_text(
|
||||
text,
|
||||
px(16.),
|
||||
|
@ -300,6 +300,7 @@ mod tests {
|
|||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let line = &lines[0];
|
||||
|
||||
let mut wrapper = LineWrapper::new(
|
||||
text_system.font_id(&normal.font).unwrap(),
|
||||
|
|
|
@ -15,11 +15,11 @@ pub(crate) struct TextLayoutCache {
|
|||
}
|
||||
|
||||
impl TextLayoutCache {
|
||||
pub fn new(fonts: Arc<dyn PlatformTextSystem>) -> Self {
|
||||
pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
|
||||
Self {
|
||||
prev_frame: Mutex::new(HashMap::new()),
|
||||
curr_frame: RwLock::new(HashMap::new()),
|
||||
platform_text_system: fonts,
|
||||
platform_text_system,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue