remove theoretically unnecessary single-line paint optimizations

This commit is contained in:
temportalflux
2026-07-11 09:31:07 -04:00
parent 06dd56bda6
commit a2e3b5f09e
+59 -217
View File
@@ -4,7 +4,7 @@ use gpui::{
ElementInputHandler, Entity, Focusable, GlobalElementId, Hitbox, HitboxBehavior, Hsla,
InspectorElementId, LayoutId, Length, MouseButton, MouseDownEvent, MouseMoveEvent,
MouseUpEvent, Pixels, Point, ScrollWheelEvent, SharedString, Style, TextAlign, TextRun,
TextStyle, Window, WrappedLine, fill, point, px, relative, size,
TextStyle, Window, fill, point, px, relative, size,
};
use std::ops::Range;
@@ -155,20 +155,6 @@ impl Element for Input {
});
let perform_paint = |_style: &Style, window: &mut Window, cx: &mut App| {
let precomputed_first_line = match (snapshot.layout, snapshot.logical_lines.first()) {
(
super::InputLayoutStyle::SingleLine,
Some(InputLogicalLine {
wrapped_line: Some(wrapped_line),
..
}),
) => Some(PrecomputedLinePosition::new(
&snapshot.content,
&**wrapped_line,
snapshot.line_height,
)),
_ => None,
};
let context = PaintContext {
snapshot,
is_focused,
@@ -177,7 +163,6 @@ impl Element for Input {
placeholder: placeholder.as_ref(),
colors: &colors,
cursor_visible: is_cursor_visible,
precomputed_first_line,
};
context.process_mouse_events(&self.input, window, cx);
window.with_content_mask(Some(ContentMask { bounds }), |window| {
@@ -236,7 +221,6 @@ struct PaintContext<'app> {
placeholder: Option<&'app SharedString>,
colors: &'app PaintColors,
cursor_visible: bool,
precomputed_first_line: Option<PrecomputedLinePosition>,
}
impl<'app> PaintContext<'app> {
@@ -377,67 +361,38 @@ impl<'app> PaintContext<'app> {
}
fn paint_selection(&self, window: &mut Window) {
match self.snapshot.layout {
super::InputLayoutStyle::MultiLine => {
for line in &self.snapshot.logical_lines {
let line_y = line.y_offset - self.snapshot.scroll_offset;
let one_line = self.snapshot.logical_lines.len() == 1;
for line in &self.snapshot.logical_lines {
let line_y = line.y_offset - self.snapshot.scroll_offset;
if !self.is_line_visible(line) {
continue;
}
if !one_line {
if !self.is_line_visible(line) {
continue;
}
if !line_intersects_range(&line.text_range, &self.snapshot.selected_range) {
continue;
}
if line.text_range.is_empty() {
const EMPTY_LINE_SELECTION_WIDTH: Pixels = px(6.);
self.paint_bounds_quad(
window,
self.colors.selection,
point(px(0.), line_y),
point(
EMPTY_LINE_SELECTION_WIDTH,
line_y + self.snapshot.line_height,
),
);
} else {
self.paint_line_range(
window,
line,
&self.snapshot.selected_range,
self.colors.selection,
px(0.),
);
}
if !line_intersects_range(&line.text_range, &self.snapshot.selected_range) {
continue;
}
}
super::InputLayoutStyle::SingleLine => {
let precomputed = self
.precomputed_first_line
.as_ref()
.expect("missing precomputed single-line");
let start_x = pos_in_string_for_char_index(
&self.snapshot.content,
&precomputed.char_positions,
self.snapshot.selected_range.start,
&precomputed.text_width,
) - self.snapshot.scroll_offset;
let end_x = pos_in_string_for_char_index(
&self.snapshot.content,
&precomputed.char_positions,
self.snapshot.selected_range.end,
&precomputed.text_width,
) - self.snapshot.scroll_offset;
let y_offset =
(self.bounds.size.height - self.snapshot.line_height).max(px(0.)) / 2.0;
if line.text_range.is_empty() {
const EMPTY_LINE_SELECTION_WIDTH: Pixels = px(6.);
self.paint_bounds_quad(
window,
self.colors.selection,
point(start_x, y_offset),
point(end_x, y_offset + self.snapshot.line_height),
point(px(0.), line_y),
point(
EMPTY_LINE_SELECTION_WIDTH,
line_y + self.snapshot.line_height,
),
);
} else {
self.paint_line_range(
window,
line,
&self.snapshot.selected_range,
self.colors.selection,
px(0.),
);
}
}
@@ -477,52 +432,26 @@ impl<'app> PaintContext<'app> {
}
fn paint_text(&self, window: &mut Window, cx: &mut App) {
match self.snapshot.layout {
super::InputLayoutStyle::MultiLine => {
for line_layout in &self.snapshot.logical_lines {
let line_y = line_layout.y_offset - self.snapshot.scroll_offset;
for line_layout in &self.snapshot.logical_lines {
let line_y = line_layout.y_offset - self.snapshot.scroll_offset;
if !self.is_line_visible(line_layout) {
continue;
}
if let Some(wrapped) = &line_layout.wrapped_line {
let paint_pos = point(self.bounds.left(), self.bounds.top() + line_y);
let _ = wrapped.paint(
paint_pos,
self.snapshot.line_height,
TextAlign::Left,
Some(self.bounds),
window,
cx,
);
}
}
if !self.is_line_visible(line_layout) {
continue;
}
super::InputLayoutStyle::SingleLine => {
let Some(line_layout) = self.snapshot.logical_lines.first() else {
return;
};
let Some(wrapped_line) = &line_layout.wrapped_line else {
return;
};
let y_offset =
(self.bounds.size.height - self.snapshot.line_height).max(px(0.)) / 2.0;
let paint_origin = point(
self.bounds.origin.x - self.snapshot.scroll_offset,
self.bounds.origin.y + y_offset,
);
let Some(wrapped) = &line_layout.wrapped_line else {
continue;
};
let _ = wrapped_line.paint(
paint_origin,
self.snapshot.line_height,
TextAlign::Left,
Some(self.bounds),
window,
cx,
);
}
let paint_pos = point(self.bounds.left(), self.bounds.top() + line_y);
let _ = wrapped.paint(
paint_pos,
self.snapshot.line_height,
TextAlign::Left,
Some(self.bounds),
window,
cx,
);
}
}
@@ -536,57 +465,26 @@ impl<'app> PaintContext<'app> {
let underline_thickness = px(MARKED_TEXT_UNDERLINE_THICKNESS);
let underline_offset = self.snapshot.line_height - underline_thickness;
match self.snapshot.layout {
super::InputLayoutStyle::MultiLine => {
for line in &self.snapshot.logical_lines {
if !self.is_line_visible(line) {
continue;
}
if !line_intersects_range(&line.text_range, marked_range) {
continue;
}
if line.text_range.is_empty() {
continue;
}
self.paint_line_range(
window,
line,
marked_range,
self.colors.cursor,
underline_offset,
);
}
for line in &self.snapshot.logical_lines {
if !self.is_line_visible(line) {
continue;
}
super::InputLayoutStyle::SingleLine => {
let Some(precomputed) = &self.precomputed_first_line else {
return;
};
let start_x = pos_in_string_for_char_index(
&self.snapshot.content,
&precomputed.char_positions,
marked_range.start,
&precomputed.text_width,
) - self.snapshot.scroll_offset;
let end_x = pos_in_string_for_char_index(
&self.snapshot.content,
&precomputed.char_positions,
marked_range.end,
&precomputed.text_width,
) - self.snapshot.scroll_offset;
let y_offset =
(self.bounds.size.height - self.snapshot.line_height).max(px(0.)) / 2.0;
self.paint_bounds_quad(
window,
self.colors.cursor,
point(start_x, y_offset + underline_offset),
point(end_x, y_offset + self.snapshot.line_height),
);
if !line_intersects_range(&line.text_range, marked_range) {
continue;
}
if line.text_range.is_empty() {
continue;
}
self.paint_line_range(
window,
line,
marked_range,
self.colors.cursor,
underline_offset,
);
}
}
@@ -626,26 +524,7 @@ impl<'app> PaintContext<'app> {
}
fn paint_cursor(&self, window: &mut Window) {
let cursor_pos = match self.snapshot.layout {
super::InputLayoutStyle::MultiLine => self.find_cursor_position_in_layouts(),
super::InputLayoutStyle::SingleLine => {
let Some(precomputed) = &self.precomputed_first_line else {
return;
};
let cursor_x = pos_in_string_for_char_index(
&self.snapshot.content,
&precomputed.char_positions,
self.snapshot.cursor_offset,
&precomputed.text_width,
) - self.snapshot.scroll_offset;
let y_offset =
(self.bounds.size.height - self.snapshot.line_height).max(px(0.)) / 2.0;
point(cursor_x, y_offset)
}
};
let cursor_pos = self.find_cursor_position_in_layouts();
window.paint_quad(fill(
Bounds::new(
point(self.bounds.left(), self.bounds.top()) + cursor_pos,
@@ -748,40 +627,3 @@ fn line_intersects_range(
selected_range.end > text_range.start && selected_range.start < text_range.end
}
}
struct PrecomputedLinePosition {
text_width: Pixels,
char_positions: Vec<Pixels>,
}
impl PrecomputedLinePosition {
fn new(string: &str, line: &WrappedLine, line_height: Pixels) -> Self {
let text_width = line.width();
let mut char_positions = Vec::new();
let mut idx = 0;
for ch in string.chars() {
if let Some(pos) = line.position_for_index(idx, line_height) {
char_positions.push(pos.x);
} else {
char_positions.push(text_width);
}
idx += ch.len_utf8();
}
char_positions.push(text_width);
Self {
text_width,
char_positions,
}
}
}
fn pos_in_string_for_char_index<'chars>(
content: &SharedString,
char_positions: &'chars Vec<Pixels>,
index: usize,
default: &Pixels,
) -> Pixels {
let char_index = content[..index.min(content.len())].chars().count();
char_positions.get(char_index).unwrap_or(default).clone()
}