Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache inline layout created by Parley #97

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion examples/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fn main() {

fn app() -> Element {
let mut count = use_signal(|| 0);
let blue = use_memo(move || if count() % 2 == 1 { "text-blue" } else { "" });

rsx! {
div {
Expand All @@ -20,7 +21,12 @@ fn app() -> Element {
linear-gradient(127deg, rgba(0,255,0,.8), rgba(0,255,0,0) 70.71%),
linear-gradient(336deg, rgba(0,0,255,.8), rgba(0,0,255,0) 70.71%)"#,
style { {CSS} }
h1 { class: "header", "Count: {count}" }
h1 { class: "header {blue}", "Count: {count}" }
span {
span { "Count: " }
span { "{count}" }
span { " clicks" }
}
div { class: "buttons",
button {
class: "counter-button btn-green",
Expand Down Expand Up @@ -70,6 +76,10 @@ h4 {
font-family: sans-serif;
}

.text-blue {
color: blue;
}

.container {
display: flex;
flex-direction: column;
Expand Down
10 changes: 8 additions & 2 deletions packages/dioxus-blitz/src/documents/dioxus_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,9 @@ impl WriteMutations for MutationWriter<'_> {
id: ElementId,
) {
let node_id = self.state.element_to_node_id(id);
if name == "style" || name == "class" || name == "id" {
self.doc.reset_styles(node_id);
}
let node = self.doc.get_node_mut(node_id).unwrap();
if let NodeData::Element(ref mut element) = node.raw_dom_data {
// FIXME: support non-text attributes
Expand Down Expand Up @@ -437,9 +440,12 @@ impl WriteMutations for MutationWriter<'_> {
let contents = text.content.clone();

if let Some(parent) = node.parent {
if changed {
self.doc.invalidate_inline_layout(parent);
}
// if the text is the child of a style element, we want to put the style into the stylesheet cache
let parent = self.doc.get_node(parent).unwrap();
if let NodeData::Element(ref element) = parent.raw_dom_data {
let parent = self.doc.get_node_mut(parent).unwrap();
if let NodeData::Element(ref mut element) = parent.raw_dom_data {
// Only set stylsheets if the text content has *changed* - we need to unload
if changed && element.name.local.as_ref() == "style" {
self.doc.add_stylesheet(value);
Expand Down
37 changes: 37 additions & 0 deletions packages/dom/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use style::invalidation::element::restyle_hints::RestyleHint;
use style::selector_parser::ServoElementSnapshot;
use style::servo::media_queries::FontMetricsProvider;
use style::servo_arc::Arc as ServoArc;
use style::values::specified::box_::DisplayOutside;
use style::{
dom::{TDocument, TNode},
media_queries::{Device, MediaList},
Expand Down Expand Up @@ -444,6 +445,12 @@ impl Document {
let hover_node_id = self.hit(x, y);

if hover_node_id != self.hover_node_id {
if let Some(new_hover_id) = hover_node_id {
self.reset_styles(new_hover_id);
}
if let Some(old_hover_id) = self.hover_node_id {
self.reset_styles(old_hover_id);
}
let mut maybe_id = self.hover_node_id;
while let Some(id) = maybe_id {
self.nodes[id].is_hovered = false;
Expand Down Expand Up @@ -498,6 +505,36 @@ impl Document {
self.stylist.device()
}

pub fn invalidate_inline_layout(&mut self, node_id: usize) {
let node = self.get_node_mut(node_id).unwrap();
let style = node.display_style();
let NodeData::Element(ref mut element) = node.raw_dom_data else {
return;
};
element.inline_layout = None;
// TODO: When let-chains lend in stable, rewrite to be nicer
let Some(style) = style else {
return;
};
let Some(parent) = node.parent else {
return;
};
if style.outside() == DisplayOutside::Inline {
self.invalidate_inline_layout(parent);
}
}

// TODO: When class, style, or hover changes, we need to clean up all the unchanged stuff in cache.
// For now, we clean up only inline layout as we don't cache other style related stuff.
pub fn reset_styles(&mut self, element_id: usize) {
self.invalidate_inline_layout(element_id);
let node = self.get_node(element_id).unwrap();
// I hate this clone
for child_id in node.children.clone().iter().copied() {
self.reset_styles(child_id);
}
}

/// Ensure that the layout_children field is populated for all nodes
pub fn resolve_layout_children(&mut self) {
let root_node_id = self.root_node().id;
Expand Down
23 changes: 17 additions & 6 deletions packages/dom/src/layout/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,25 @@ pub(crate) fn collect_layout_children(

// TODO: fix display:contents
if all_inline {
let (inline_layout, ilayout_children) = build_inline_layout(doc, container_node_id);
doc.nodes[container_node_id].is_inline_root = true;
doc.nodes[container_node_id]
// Caching because calling Parley is expensive
if doc.nodes[container_node_id]
.raw_dom_data
.downcast_element_mut()
.downcast_element()
.unwrap()
.inline_layout = Some(Box::new(inline_layout));
return layout_children.extend_from_slice(&ilayout_children);
.inline_layout
.is_none()
{
let (inline_layout, ilayout_children) =
build_inline_layout(doc, container_node_id);
doc.nodes[container_node_id].is_inline_root = true;
doc.nodes[container_node_id]
.raw_dom_data
.downcast_element_mut()
.unwrap()
.inline_layout = Some(Box::new(inline_layout));
layout_children.extend_from_slice(&ilayout_children);
}
return;
}

// If the children are either all inline or all block then simply return the regular children
Expand Down