Skip to content

Commit

Permalink
refactor: Per node states and lazy scaling (#1103)
Browse files Browse the repository at this point in the history
* refactor: Split and unify node states per their tag name, and add lazy scaling

* fix: Dont check for cursor state in mutations writer

* fix test

* fix another test

* fix another test
  • Loading branch information
marc2332 authored Feb 9, 2025
1 parent 8f5db55 commit 82fa2aa
Show file tree
Hide file tree
Showing 36 changed files with 478 additions and 245 deletions.
Binary file modified crates/components/images/gallery_enabled_switch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion crates/components/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,6 @@ pub fn Input(
corner_radius: "{corner_radius}",
margin: "{margin}",
main_align: "center",
cursor_reference,
a11y_id,
a11y_role: "text-input",
a11y_auto_focus: "{auto_focus}",
Expand All @@ -364,6 +363,7 @@ pub fn Input(
onglobalclick,
onmousedown,
onglobalmousemove,
cursor_reference,
cursor_id: "0",
cursor_index: "{cursor_char}",
cursor_mode: "editable",
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/dom/dom_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl DOMAdapter<NodeId> for DioxusDOMAdapter<'_> {
spacing: layout.spacing,
};

node.scale(self.scale_factor);
node.scale_if_needed(self.scale_factor);

Some(node)
}
Expand Down
8 changes: 6 additions & 2 deletions crates/core/src/dom/doms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ use crate::{
},
states::{
AccessibilityNodeState,
CanvasState,
CursorState,
FontStyleState,
ImageState,
LayerState,
LayoutState,
ReferencesState,
StyleState,
SvgState,
TransformState,
ViewportState,
},
Expand Down Expand Up @@ -146,13 +148,15 @@ impl Default for FreyaDOM {
let mut rdom = RealDom::<CustomAttributeValues>::new([
CursorState::to_type_erased(),
FontStyleState::to_type_erased(),
ReferencesState::to_type_erased(),
CanvasState::to_type_erased(),
LayoutState::to_type_erased(),
StyleState::to_type_erased(),
TransformState::to_type_erased(),
AccessibilityNodeState::to_type_erased(),
ViewportState::to_type_erased(),
LayerState::to_type_erased(),
SvgState::to_type_erased(),
ImageState::to_type_erased(),
]);
let dioxus_integration_state = DioxusState::create(&mut rdom);
Self {
Expand Down
21 changes: 11 additions & 10 deletions crates/core/src/dom/mutations_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ use crate::{
},
states::{
CursorState,
ImageState,
LayerState,
StyleState,
},
};

Expand Down Expand Up @@ -69,9 +69,8 @@ impl<'a> MutationsWriter<'a> {
}

let layer_state = node.get::<LayerState>();
let cursor_state = node.get::<CursorState>();

let Some((layer_state, cursor_state)) = layer_state.zip(cursor_state) else {
let Some(layer_state) = layer_state else {
// There might exist Nodes in the RealDOM with no states yet,
// this is mainly due to nodes being created in the same run as when this function (remove) is being called,
// like nodes created by loaded templates.
Expand All @@ -94,9 +93,11 @@ impl<'a> MutationsWriter<'a> {
.remove_node_from_layer(node_id, layer_state.layer);

// Remove from paragraph elements
if let Some(cursor_ref) = cursor_state.cursor_ref.as_ref() {
self.paragraphs
.remove_paragraph(node_id, &cursor_ref.text_id);
if let Some(cursor_state) = node.get::<CursorState>() {
if let Some(cursor_ref) = cursor_state.cursor_ref.as_ref() {
self.paragraphs
.remove_paragraph(node_id, &cursor_ref.text_id);
}
}

// Remove from the accessibility tree
Expand All @@ -120,10 +121,10 @@ impl<'a> MutationsWriter<'a> {
// Remove the node from the compositor cache
self.compositor_cache.remove(&node_id);

let style = node.get::<StyleState>().unwrap();

if let Some(image_cache_key) = &style.image_cache_key {
self.images_cache.remove(image_cache_key);
if let Some(image_state) = node.get::<ImageState>() {
if let Some(image_cache_key) = &image_state.image_cache_key {
self.images_cache.remove(image_cache_key);
}
}
}
}
Expand Down
12 changes: 4 additions & 8 deletions crates/core/src/elements/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ use crate::{
get_or_create_image,
ImageData,
},
states::{
StyleState,
TransformState,
},
states::ImageState,
values::{
ImageCover,
SamplingMode,
Expand Down Expand Up @@ -43,8 +40,7 @@ impl ElementUtils for ImageElement {
return;
};

let node_transform = node_ref.get::<TransformState>().unwrap();
let node_style = node_ref.get::<StyleState>().unwrap();
let image_state = node_ref.get::<ImageState>().unwrap();

let mut rect = Rect::new(
area.min_x(),
Expand All @@ -55,7 +51,7 @@ impl ElementUtils for ImageElement {

let clip_rect = Rect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y());

if node_transform.image_cover == ImageCover::Center {
if image_state.image_cover == ImageCover::Center {
let width_offset = (size.width - area.width()) / 2.;
let height_offset = (size.height - area.height()) / 2.;

Expand All @@ -71,7 +67,7 @@ impl ElementUtils for ImageElement {
let mut paint = Paint::default();
paint.set_anti_alias(true);

let sampling = match node_style.image_sampling {
let sampling = match image_state.image_sampling {
SamplingMode::Nearest => SamplingOptions::new(FilterMode::Nearest, MipmapMode::None),
SamplingMode::Bilinear => SamplingOptions::new(FilterMode::Linear, MipmapMode::None),
SamplingMode::Trilinear => SamplingOptions::new(FilterMode::Linear, MipmapMode::Linear),
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/elements/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl ElementUtils for LabelElement {

let mut text_shadow_area = area;

for text_shadow in &font_style.text_shadows {
for text_shadow in font_style.text_shadows.iter() {
text_shadow_area.move_with_offsets(
&Length::new(text_shadow.offset.x),
&Length::new(text_shadow.offset.y),
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/elements/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ impl ElementUtils for ParagraphElement {

let mut text_shadow_area = area;

for text_shadow in &font_style.text_shadows {
for text_shadow in font_style.text_shadows.iter() {
if text_shadow.color != Color::TRANSPARENT {
text_shadow_area.move_with_offsets(
&Length::new(text_shadow.offset.x),
Expand Down
44 changes: 19 additions & 25 deletions crates/core/src/elements/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{
BorderShape,
},
states::{
ReferencesState,
CanvasState,
StyleState,
},
values::{
Expand All @@ -45,8 +45,7 @@ impl RectElement {
) -> RRect {
let area = layout_node.visible_area().to_f32();
let node_style = &*node_ref.get::<StyleState>().unwrap();
let mut radius = node_style.corner_radius;
radius.scale(scale_factor);
let radius = node_style.corner_radius.with_scale(scale_factor);

RRect::new_rect_radii(
Rect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
Expand Down Expand Up @@ -106,8 +105,7 @@ impl ElementUtils for RectElement {

node_style.background.apply_to_paint(&mut paint, area);

let mut corner_radius = node_style.corner_radius;
corner_radius.scale(scale_factor);
let corner_radius = node_style.corner_radius.with_scale(scale_factor);

// Container
let rounded_rect = RRect::new_rect_radii(
Expand All @@ -131,33 +129,33 @@ impl ElementUtils for RectElement {
canvas.draw_path(&path, &paint);

// Shadows
for mut shadow in node_style.shadows.clone().into_iter() {
for shadow in node_style.shadows.iter() {
if shadow.fill != Fill::Color(Color::TRANSPARENT) {
shadow.scale(scale_factor);
let shadow = shadow.with_scale(scale_factor);

render_shadow(
canvas,
node_style,
&mut path,
rounded_rect,
area,
shadow,
corner_radius,
&shadow,
&corner_radius,
);
}
}

// Borders
for mut border in node_style.borders.clone().into_iter() {
for border in node_style.borders.iter() {
if border.is_visible() {
border.scale(scale_factor);
let border = border.with_scale(scale_factor);

render_border(canvas, rounded_rect, area, &border, corner_radius);
render_border(canvas, rounded_rect, area, &border, &corner_radius);
}
}

// Layout references
let references = node_ref.get::<ReferencesState>().unwrap();
// Canvas reference
let references = node_ref.get::<CanvasState>().unwrap();
if let Some(canvas_ref) = &references.canvas_ref {
let mut ctx = CanvasRunnerContext {
canvas,
Expand Down Expand Up @@ -189,8 +187,7 @@ impl ElementUtils for RectElement {

let mut path = Path::new();

let mut corner_radius = node_style.corner_radius;
corner_radius.scale(scale_factor);
let corner_radius = node_style.corner_radius.with_scale(scale_factor);

let rounded_rect = RRect::new_rect_radii(
Rect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
Expand All @@ -213,9 +210,9 @@ impl ElementUtils for RectElement {
}

// Shadows
for mut shadow in node_style.shadows.clone().into_iter() {
for shadow in node_style.shadows.iter() {
if shadow.fill != Fill::Color(Color::TRANSPARENT) {
shadow.scale(scale_factor);
let shadow = shadow.with_scale(scale_factor);

let mut shadow_path = Path::new();

Expand All @@ -234,9 +231,7 @@ impl ElementUtils for RectElement {
// Add either the RRect or smoothed path based on whether smoothing is used.
if corner_radius.smoothing > 0.0 {
shadow_path.add_path(
&node_style
.corner_radius
.smoothed_path(rounded_rect.with_outset(outset)),
&corner_radius.smoothed_path(rounded_rect.with_outset(outset)),
Point::new(area.min_x(), area.min_y()) - outset,
None,
);
Expand All @@ -261,12 +256,11 @@ impl ElementUtils for RectElement {
}
}

for mut border in node_style.borders.clone().into_iter() {
for border in node_style.borders.iter() {
if border.is_visible() {
border.scale(scale_factor);
let border = border.with_scale(scale_factor);

let border_shape =
border_shape(*rounded_rect.rect(), node_style.corner_radius, &border);
let border_shape = border_shape(*rounded_rect.rect(), &corner_radius, &border);
let border_bounds = match border_shape {
BorderShape::DRRect(ref outer, _) => outer.bounds(),
BorderShape::Path(ref path) => path.bounds(),
Expand Down
10 changes: 5 additions & 5 deletions crates/core/src/elements/svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
},
states::{
FontStyleState,
StyleState,
SvgState,
},
};

Expand All @@ -29,12 +29,12 @@ impl ElementUtils for SvgElement {
_scale_factor: f32,
) {
let area = layout_node.visible_area();
let node_style = &*node_ref.get::<StyleState>().unwrap();
let svg_state = &*node_ref.get::<SvgState>().unwrap();
let font_style = &*node_ref.get::<FontStyleState>().unwrap();

let x = area.min_x();
let y = area.min_y();
if let Some(svg_data) = &node_style.svg_data {
if let Some(svg_data) = &svg_state.svg_data {
let resource_provider = LocalResourceProvider::new(font_manager);
let svg_dom = svg::Dom::from_bytes(svg_data.as_slice(), resource_provider);
if let Ok(mut svg_dom) = svg_dom {
Expand All @@ -45,10 +45,10 @@ impl ElementUtils for SvgElement {
root.set_width(svg::Length::new(100.0, svg::LengthUnit::Percentage));
root.set_height(svg::Length::new(100.0, svg::LengthUnit::Percentage));
root.set_color(font_style.color);
if let Some(color) = node_style.svg_stroke.as_ref() {
if let Some(color) = svg_state.svg_stroke.as_ref() {
root.set_fill(svg::Paint::from_color(*color));
}
if let Some(color) = node_style.svg_fill.as_ref() {
if let Some(color) = svg_state.svg_fill.as_ref() {
root.set_stroke(svg::Paint::from_color(*color));
}
svg_dom.render(canvas);
Expand Down
Loading

0 comments on commit 82fa2aa

Please sign in to comment.