Skip to content

Commit

Permalink
feat: Use the actual text font height to invalidate the areas of text…
Browse files Browse the repository at this point in the history
…s instead of the one given by the line height
  • Loading branch information
marc2332 committed Aug 29, 2024
1 parent daf1391 commit 55714e9
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 28 deletions.
2 changes: 1 addition & 1 deletion crates/common/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub enum CursorLayoutResponse {
TextSelection { from: usize, to: usize, id: usize },
}

pub struct CachedParagraph(pub Paragraph);
pub struct CachedParagraph(pub Paragraph, pub f32);

/// # Safety
/// Skia `Paragraph` are neither Sync or Send, but in order to store them in the Associated
Expand Down
11 changes: 10 additions & 1 deletion crates/core/src/elements/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,16 @@ impl ElementUtils for LabelElement {
node_ref: &DioxusNode,
scale_factor: f32,
) -> Area {
let area = layout_node.visible_area();
let paragraph_font_height = &layout_node
.data
.as_ref()
.unwrap()
.get::<CachedParagraph>()
.unwrap()
.1;
let mut area = layout_node.visible_area();
area.size.height = area.size.height.max(*paragraph_font_height);

let font_style = node_ref.get::<FontStyleState>().unwrap();

let mut text_shadow_area = area;
Expand Down
10 changes: 9 additions & 1 deletion crates/core/src/elements/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl ElementUtils for ParagraphElement {
};

if node_cursor_state.position.is_some() {
let paragraph = create_paragraph(
let (paragraph, _) = create_paragraph(
node_ref,
&area.size,
font_collection,
Expand Down Expand Up @@ -182,7 +182,15 @@ impl ElementUtils for ParagraphElement {
node_ref: &DioxusNode,
scale_factor: f32,
) -> Area {
let paragraph_font_height = &layout_node
.data
.as_ref()
.unwrap()
.get::<CachedParagraph>()
.unwrap()
.1;
let mut area = layout_node.visible_area();
area.size.height = area.size.height.max(*paragraph_font_height);

// Iterate over all the text spans inside this paragraph and if any of them
// has a shadow at all, apply this shadow to the general paragraph.
Expand Down
51 changes: 38 additions & 13 deletions crates/core/src/render/skia_measurer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,21 @@ impl<'a> LayoutMeasurer<NodeId> for SkiaMeasurer<'a> {

match &*node_type {
NodeType::Element(ElementNode { tag, .. }) if tag == &TagName::Label => {
let label = create_label(
let (label, paragraph_font_height) = create_label(
&node,
area_size,
self.font_collection,
self.default_fonts,
self.scale_factor,
);

let res = Size2D::new(label.longest_line(), label.height());
let mut map = SendAnyMap::new();
map.insert(CachedParagraph(label));
map.insert(CachedParagraph(label, paragraph_font_height));
Some((res, Arc::new(map)))
}
NodeType::Element(ElementNode { tag, .. }) if tag == &TagName::Paragraph => {
let paragraph = create_paragraph(
let (paragraph, paragraph_font_height) = create_paragraph(
&node,
area_size,
self.font_collection,
Expand All @@ -92,7 +93,7 @@ impl<'a> LayoutMeasurer<NodeId> for SkiaMeasurer<'a> {
);
let res = Size2D::new(paragraph.longest_line(), paragraph.height());
let mut map = SendAnyMap::new();
map.insert(CachedParagraph(paragraph));
map.insert(CachedParagraph(paragraph, paragraph_font_height));
Some((res, Arc::new(map)))
}
_ => None,
Expand Down Expand Up @@ -130,20 +131,21 @@ pub fn create_label(
font_collection: &FontCollection,
default_font_family: &[String],
scale_factor: f32,
) -> Paragraph {
) -> (Paragraph, f32) {
let font_style = &*node.get::<FontStyleState>().unwrap();

let mut paragraph_style = ParagraphStyle::default();
paragraph_style.set_text_align(font_style.text_align);
paragraph_style.set_max_lines(font_style.max_lines);
paragraph_style.set_replace_tab_characters(true);
let text_style = font_style.text_style(default_font_family, scale_factor);
paragraph_style.set_text_style(&text_style);

if let Some(ellipsis) = font_style.text_overflow.get_ellipsis() {
paragraph_style.set_ellipsis(ellipsis);
}

let text_style = font_style.text_style(default_font_family, scale_factor, true);
paragraph_style.set_text_style(&text_style);

let mut paragraph_builder = ParagraphBuilder::new(&paragraph_style, font_collection);

for child in node.children() {
Expand All @@ -154,7 +156,17 @@ pub fn create_label(

let mut paragraph = paragraph_builder.build();
paragraph.layout(area_size.width + 1.0);
paragraph

// Measure the actual text height, ignoring the line height
let mut height = paragraph.height();
for line in paragraph.get_line_metrics() {
for (_, text) in line.get_style_metrics(0..1) {
let text_height = -(text.font_metrics.ascent - text.font_metrics.descent);
height = height.max(text_height);
}
}

(paragraph, height)
}

/// Align the Y axis of the highlights and cursor of a paragraph
Expand Down Expand Up @@ -212,7 +224,7 @@ pub fn create_paragraph(
is_rendering: bool,
default_font_family: &[String],
scale_factor: f32,
) -> Paragraph {
) -> (Paragraph, f32) {
let font_style = &*node.get::<FontStyleState>().unwrap();

let mut paragraph_style = ParagraphStyle::default();
Expand All @@ -226,10 +238,13 @@ pub fn create_paragraph(

let mut paragraph_builder = ParagraphBuilder::new(&paragraph_style, font_collection);

let text_style = font_style.text_style(default_font_family, scale_factor);
let text_style = font_style.text_style(default_font_family, scale_factor, true);
paragraph_builder.push_style(&text_style);

for text_span in node.children() {
let node_children = node.children();
let node_children_len = node_children.len();

for text_span in node_children {
if let NodeType::Element(ElementNode {
tag: TagName::Text, ..
}) = &*text_span.node_type()
Expand All @@ -238,7 +253,7 @@ pub fn create_paragraph(
let text_node = *text_nodes.first().unwrap();
let text_node_type = &*text_node.node_type();
let font_style = text_span.get::<FontStyleState>().unwrap();
let text_style = font_style.text_style(default_font_family, scale_factor);
let text_style = font_style.text_style(default_font_family, scale_factor, true);
paragraph_builder.push_style(&text_style);

if let NodeType::Text(text) = text_node_type {
Expand All @@ -254,5 +269,15 @@ pub fn create_paragraph(

let mut paragraph = paragraph_builder.build();
paragraph.layout(area_size.width + 1.0);
paragraph

// Measure the actual text height, ignoring the line height
let mut height = paragraph.height();
for line in paragraph.get_line_metrics() {
for (_, text) in line.get_style_metrics(0..node_children_len) {
let text_height = -(text.font_metrics.ascent - text.font_metrics.descent);
height = height.max(text_height);
}
}

(paragraph, height)
}
13 changes: 9 additions & 4 deletions crates/state/src/font_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ pub struct FontStyleState {
}

impl FontStyleState {
pub fn text_style(&self, default_font_family: &[String], scale_factor: f32) -> TextStyle {
pub fn text_style(
&self,
default_font_family: &[String],
scale_factor: f32,
height_override: bool,
) -> TextStyle {
let mut text_style = TextStyle::new();
let mut font_family = self.font_family.clone();

Expand All @@ -65,7 +70,7 @@ impl FontStyleState {
.set_font_families(&font_family)
.set_word_spacing(self.word_spacing)
.set_letter_spacing(self.letter_spacing)
.set_height_override(true)
.set_height_override(height_override)
.set_height(self.line_height);

for text_shadow in self.text_shadows.iter() {
Expand Down Expand Up @@ -143,8 +148,8 @@ impl ParseAttribute for FontStyleState {
}
AttributeName::LineHeight => {
if let Some(value) = attr.value.as_text() {
if let Ok(line_height) = value.parse() {
self.line_height = line_height;
if let Ok(line_height) = value.parse::<f32>() {
self.line_height = line_height.max(1.0);
}
}
}
Expand Down
37 changes: 29 additions & 8 deletions examples/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,35 @@ fn app() -> Element {

rsx!(
rect {
height: "50%",
width: "100%",
main_align: "center",
cross_align: "center",
background: "rgb(0, 119, 182)",
color: "white",
shadow: "0 4 20 5 rgb(0, 0, 0, 80)",
Loader {}
rect {
height: "50%",
width: "100%",
main_align: "center",
cross_align: "center",
background: "rgb(0, 119, 182)",
color: "white",
shadow: "0 4 20 5 rgb(0, 0, 0, 80)",
label {
font_size: "75",
font_weight: "bold",
"{count}"
}
}
rect {
height: "50%",
width: "100%",
main_align: "center",
cross_align: "center",
direction: "horizontal",
Button {
onclick: move |_| count += 1,
label { "Increase" }
}
Button {
onclick: move |_| count -= 1,
label { "Decrease" }
}
}
}
)
}

0 comments on commit 55714e9

Please sign in to comment.