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

Optimise layout performance #1722

Closed
wants to merge 7 commits into from
Closed
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
4 changes: 2 additions & 2 deletions examples/modal/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ mod modal {
cursor_position: Point,
viewport: &Rectangle,
) {
self.base.as_widget().draw(
self.base.as_widget_mut().draw(
&state.children[0],
renderer,
theme,
Expand Down Expand Up @@ -424,7 +424,7 @@ mod modal {
},
);

self.content.as_widget().draw(
self.content.as_widget_mut().draw(
self.tree,
renderer,
theme,
Expand Down
4 changes: 2 additions & 2 deletions examples/toast/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ mod toast {
cursor_position: Point,
viewport: &Rectangle,
) {
self.content.as_widget().draw(
self.content.as_widget_mut().draw(
&state.children[0],
renderer,
theme,
Expand Down Expand Up @@ -597,7 +597,7 @@ mod toast {
.zip(self.state.iter())
.zip(layout.children())
{
child.as_widget().draw(
child.as_widget_mut().draw(
state,
renderer,
theme,
Expand Down
4 changes: 2 additions & 2 deletions graphics/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ where

fn layout<Message>(
&mut self,
element: &Element<'_, Message, Self>,
element: &mut Element<'_, Message, Self>,
limits: &layout::Limits,
) -> layout::Node {
let layout = element.as_widget().layout(self, limits);
let layout = element.as_widget_mut().layout(self, limits);

self.backend.trim_measurements();

Expand Down
2 changes: 1 addition & 1 deletion lazy/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ where
viewport: &Rectangle,
) {
self.with_element(|element| {
element.as_widget().draw(
element.as_widget_mut().draw(
&tree.children[0],
renderer,
theme,
Expand Down
2 changes: 1 addition & 1 deletion lazy/src/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ where
viewport: &Rectangle,
) {
self.with_element(|element| {
element.as_widget().draw(
element.as_widget_mut().draw(
&tree.children[0],
renderer,
theme,
Expand Down
2 changes: 1 addition & 1 deletion lazy/src/responsive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ where
layout,
&self.view,
|tree, renderer, layout, element| {
element.as_widget().draw(
element.as_widget_mut().draw(
tree,
renderer,
theme,
Expand Down
18 changes: 13 additions & 5 deletions native/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::renderer;
use crate::widget;
use crate::widget::tree::{self, Tree};
use crate::{
Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Widget,
Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Size, Widget,
};

use std::any::Any;
Expand Down Expand Up @@ -280,13 +280,21 @@ where
}

fn layout(
&self,
&mut self,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
self.widget.layout(renderer, limits)
}

fn measure(
&mut self,
renderer: &Renderer,
limits: &layout::Limits,
) -> Size {
self.widget.measure(renderer, limits)
}

fn operate(
&self,
tree: &mut Tree,
Expand Down Expand Up @@ -377,7 +385,7 @@ where
}

fn draw(
&self,
&mut self,
tree: &Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
Expand Down Expand Up @@ -472,7 +480,7 @@ where
}

fn layout(
&self,
&mut self,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
Expand Down Expand Up @@ -513,7 +521,7 @@ where
}

fn draw(
&self,
&mut self,
state: &Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
Expand Down
61 changes: 47 additions & 14 deletions native/src/layout/flex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ impl Axis {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Whether a full (recursive) layout should be performed or the size of the container measured
pub enum LayoutMode {
/// Only the size of the container needs to be measured
MeasureSize,
/// A full recursive layout should be performed
PerformLayout,
}

/// Computes the flex layout with the given axis and limits, applying spacing,
/// padding and alignment to the items as needed.
///
Expand All @@ -65,7 +74,8 @@ pub fn resolve<Message, Renderer>(
padding: Padding,
spacing: f32,
align_items: Alignment,
items: &[Element<'_, Message, Renderer>],
items: &mut [Element<'_, Message, Renderer>],
mode: LayoutMode,
) -> Node
where
Renderer: crate::Renderer,
Expand All @@ -84,7 +94,7 @@ where
if align_items == Alignment::Fill {
let mut fill_cross = axis.cross(limits.min());

items.iter().for_each(|child| {
items.iter_mut().for_each(|child| {
let cross_fill_factor = match axis {
Axis::Horizontal => child.as_widget().height(),
Axis::Vertical => child.as_widget().width(),
Expand All @@ -97,8 +107,8 @@ where
let child_limits =
Limits::new(Size::ZERO, Size::new(max_width, max_height));

let layout = child.as_widget().layout(renderer, &child_limits);
let size = layout.size();
let size =
child.as_widget_mut().measure(renderer, &child_limits);

fill_cross = fill_cross.max(axis.cross(size));
}
Expand All @@ -107,7 +117,7 @@ where
cross = fill_cross;
}

for (i, child) in items.iter().enumerate() {
for (i, child) in items.iter_mut().enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.as_widget().width(),
Axis::Vertical => child.as_widget().height(),
Expand All @@ -132,24 +142,35 @@ where
Size::new(max_width, max_height),
);

let layout = child.as_widget().layout(renderer, &child_limits);
let size = layout.size();
let size = match mode {
LayoutMode::MeasureSize => {
let size =
child.as_widget_mut().measure(renderer, &child_limits);
nodes[i] = Node::new(size);
size
}
LayoutMode::PerformLayout => {
let layout =
child.as_widget_mut().layout(renderer, &child_limits);
let size = layout.size();
nodes[i] = layout;
size
}
};

available -= axis.main(size);

if align_items != Alignment::Fill {
cross = cross.max(axis.cross(size));
}

nodes[i] = layout;
} else {
fill_sum += fill_factor;
}
}

let remaining = available.max(0.0);

for (i, child) in items.iter().enumerate() {
for (i, child) in items.iter_mut().enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.as_widget().width(),
Axis::Vertical => child.as_widget().height(),
Expand Down Expand Up @@ -181,13 +202,25 @@ where
Size::new(max_width, max_height),
);

let layout = child.as_widget().layout(renderer, &child_limits);
let size = match mode {
LayoutMode::MeasureSize => {
let size =
child.as_widget_mut().measure(renderer, &child_limits);
nodes[i] = Node::new(size);
size
}
LayoutMode::PerformLayout => {
let layout =
child.as_widget_mut().layout(renderer, &child_limits);
let size = layout.size();
nodes[i] = layout;
size
}
};

if align_items != Alignment::Fill {
cross = cross.max(axis.cross(layout.size()));
cross = cross.max(axis.cross(size));
}

nodes[i] = layout;
}
}

Expand Down
13 changes: 12 additions & 1 deletion native/src/layout/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ impl Node {
self.bounds
}

/// Returns the children of the [`Node`].
/// Returns a view into the children of the [`Node`].
pub fn children(&self) -> &[Node] {
&self.children
}

/// Consumes the [`Node`] and returns the children of the [`Node`].
pub fn into_children(self) -> Vec<Node> {
self.children
}

/// Aligns the [`Node`] in the given space.
pub fn align(
&mut self,
Expand Down Expand Up @@ -81,6 +86,12 @@ impl Node {
self.bounds.y = position.y;
}

/// Set the [`Node`] to the given size.
pub fn set_size(&mut self, size: Size) {
self.bounds.width = size.width;
self.bounds.height = size.height;
}

/// Translates the [`Node`] by the given translation.
pub fn translate(self, translation: Vector) -> Self {
Self {
Expand Down
4 changes: 2 additions & 2 deletions native/src/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ where
///
/// [`Node`]: layout::Node
fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
position: Point,
) -> layout::Node;

/// Draws the [`Overlay`] using the associated `Renderer`.
fn draw(
&self,
&mut self,
renderer: &mut Renderer,
theme: &Renderer::Theme,
style: &renderer::Style,
Expand Down
8 changes: 4 additions & 4 deletions native/src/overlay/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ where

/// Computes the layout of the [`Element`] in the given bounds.
pub fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
translation: Vector,
Expand Down Expand Up @@ -101,7 +101,7 @@ where

/// Draws the [`Element`] and its children using the given [`Layout`].
pub fn draw(
&self,
&mut self,
renderer: &mut Renderer,
theme: &Renderer::Theme,
style: &renderer::Style,
Expand Down Expand Up @@ -147,7 +147,7 @@ where
Renderer: crate::Renderer,
{
fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
position: Point,
Expand Down Expand Up @@ -253,7 +253,7 @@ where
}

fn draw(
&self,
&mut self,
renderer: &mut Renderer,
theme: &Renderer::Theme,
style: &renderer::Style,
Expand Down
8 changes: 4 additions & 4 deletions native/src/overlay/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ where
Renderer: crate::Renderer,
{
fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
position: Point,
Expand All @@ -73,7 +73,7 @@ where
layout::Node::with_children(
bounds,
self.children
.iter()
.iter_mut()
.map(|child| child.layout(renderer, bounds, translation))
.collect(),
)
Expand Down Expand Up @@ -105,14 +105,14 @@ where
}

fn draw(
&self,
&mut self,
renderer: &mut Renderer,
theme: &<Renderer as crate::Renderer>::Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
) {
for (child, layout) in self.children.iter().zip(layout.children()) {
for (child, layout) in self.children.iter_mut().zip(layout.children()) {
child.draw(renderer, theme, style, layout, cursor_position);
}
}
Expand Down
Loading