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

Explicit text caching #2058

Merged
merged 28 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ed34543
Implement explicit text caching in the widget state tree
hecrj Aug 30, 2023
89acf02
Use `min_bounds` for cached text
hecrj Aug 30, 2023
c44611c
Fix vertical alignment in `layout::next_to_each_other`
hecrj Aug 30, 2023
ffd0f4d
Add some default spacing for `Toggler`
hecrj Aug 30, 2023
301e6e5
Reduce default spacing of `Checkbox`
hecrj Aug 30, 2023
a026e91
Make `widget::Tree` mutable in `Widget::layout`
hecrj Aug 30, 2023
bcd9fdb
Simplify new logic in `TextInput`
hecrj Aug 30, 2023
b51ffe5
Fix unnecessary dereference in `widget::text`
hecrj Aug 30, 2023
252a05c
Update `CHANGELOG`
hecrj Aug 30, 2023
ce22d66
Remove `Clone` implementation for `Paragraph`
hecrj Sep 1, 2023
935c722
Use `Arc::try_unwrap` in `Paragraph`
hecrj Sep 1, 2023
51e69d7
Replace `MaybeUninit` with `Option` in `paragraph`
hecrj Sep 1, 2023
6758de2
Fix `Default` implementation for `Paragraph`
hecrj Sep 1, 2023
548b9d0
Fix `Widget::layout` for `Component`
hecrj Sep 1, 2023
601e556
Fix `Widget::layout` for `Lazy`
hecrj Sep 1, 2023
8129e2c
Implement `draw_paragraph` in `iced_tiny_skia`
hecrj Sep 3, 2023
1a1da6a
Remove unnecessary mutable reference in `iced_tiny_skia`
hecrj Sep 3, 2023
34495bb
Introduce `keyed::Column` widget
hecrj Sep 4, 2023
837529b
Fix Wasm build of `todos` example
hecrj Sep 4, 2023
3450987
Invalidate existing paragraphs when new fonts are loaded
hecrj Sep 9, 2023
3cc605b
Implement `Icon` support for `TextInput`
hecrj Sep 9, 2023
bbb9c2d
Count grapheme clusters in `Paragraph::grapheme_position`
hecrj Sep 9, 2023
9565123
Remove unused `unicode-segmentation` dependency from `iced_graphics`
hecrj Sep 9, 2023
b8e5693
Merge branch 'master' into explicit-text-caching
hecrj Sep 9, 2023
8aa7874
Fix Wasm build of `todos` example
hecrj Sep 9, 2023
c692845
Fix broken intradoc link in `widget::keyed` module
hecrj Sep 9, 2023
b42b24b
Fix (more) broken intradoc links
hecrj Sep 9, 2023
1cc5bf5
Fix `CHANGELOG`
hecrj Sep 9, 2023
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Explicit text caching. [#2058](https://github.com/iced-rs/iced/pull/2058)

Many thanks to...

- Add your name here

## [0.10.0] - 2023-07-28
### Added
- Text shaping, font fallback, and `iced_wgpu` overhaul. [#1697](https://github.com/iced-rs/iced/pull/1697)
Expand Down
6 changes: 4 additions & 2 deletions core/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,11 @@ where

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

fn operate(
Expand Down Expand Up @@ -491,10 +492,11 @@ where

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

fn operate(
Expand Down
35 changes: 34 additions & 1 deletion core/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub mod flex;
pub use limits::Limits;
pub use node::Node;

use crate::{Point, Rectangle, Vector};
use crate::{Point, Rectangle, Size, Vector};

/// The bounds of a [`Node`] and its children, using absolute coordinates.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -63,3 +63,36 @@ impl<'a> Layout<'a> {
})
}
}

/// Produces a [`Node`] with two children nodes one right next to each other.
pub fn next_to_each_other(
limits: &Limits,
spacing: f32,
left: impl FnOnce(&Limits) -> Node,
right: impl FnOnce(&Limits) -> Node,
) -> Node {
let mut left_node = left(limits);
let left_size = left_node.size();

let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));

let mut right_node = right(&right_limits);
let right_size = right_node.size();

let (left_y, right_y) = if left_size.height > right_size.height {
(0.0, (left_size.height - right_size.height) / 2.0)
} else {
((right_size.height - left_size.height) / 2.0, 0.0)
};

left_node.move_to(Point::new(0.0, left_y));
right_node.move_to(Point::new(left_size.width + spacing, right_y));

Node::with_children(
Size::new(
left_size.width + spacing + right_size.width,
left_size.height.max(right_size.height),
),
vec![left_node, right_node],
)
}
12 changes: 8 additions & 4 deletions core/src/layout/flex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use crate::Element;

use crate::layout::{Limits, Node};
use crate::widget;
use crate::{Alignment, Padding, Point, Size};

/// The main axis of a flex layout.
Expand Down Expand Up @@ -66,6 +67,7 @@ pub fn resolve<Message, Renderer>(
spacing: f32,
align_items: Alignment,
items: &[Element<'_, Message, Renderer>],
trees: &mut [widget::Tree],
) -> Node
where
Renderer: crate::Renderer,
Expand All @@ -81,7 +83,7 @@ where
let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
nodes.resize(items.len(), Node::default());

for (i, child) in items.iter().enumerate() {
for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.as_widget().width(),
Axis::Vertical => child.as_widget().height(),
Expand All @@ -94,7 +96,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 layout =
child.as_widget().layout(tree, renderer, &child_limits);
let size = layout.size();

available -= axis.main(size);
Expand All @@ -108,7 +111,7 @@ where

let remaining = available.max(0.0);

for (i, child) in items.iter().enumerate() {
for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.as_widget().width(),
Axis::Vertical => child.as_widget().height(),
Expand All @@ -133,7 +136,8 @@ where
Size::new(max_width, max_height),
);

let layout = child.as_widget().layout(renderer, &child_limits);
let layout =
child.as_widget().layout(tree, renderer, &child_limits);
cross = cross.max(axis.cross(layout.size()));

nodes[i] = layout;
Expand Down
2 changes: 1 addition & 1 deletion core/src/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ where
///
/// [`Node`]: layout::Node
fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
position: Point,
Expand Down
4 changes: 2 additions & 2 deletions core/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 @@ -150,7 +150,7 @@ where
Renderer: crate::Renderer,
{
fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
position: Point,
Expand Down
4 changes: 2 additions & 2 deletions core/src/overlay/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ where
Renderer: crate::Renderer,
{
fn layout(
&self,
&mut self,
renderer: &Renderer,
bounds: Size,
position: Point,
Expand All @@ -71,7 +71,7 @@ where
layout::Node::with_children(
bounds,
self.children
.iter()
.iter_mut()
.map(|child| child.layout(renderer, bounds, translation))
.collect(),
)
Expand Down
15 changes: 1 addition & 14 deletions core/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,13 @@ mod null;
#[cfg(debug_assertions)]
pub use null::Null;

use crate::layout;
use crate::{Background, BorderRadius, Color, Element, Rectangle, Vector};
use crate::{Background, BorderRadius, Color, Rectangle, Vector};

/// A component that can be used by widgets to draw themselves on a screen.
pub trait Renderer: Sized {
/// The supported theme of the [`Renderer`].
type Theme;

/// Lays out the elements of a user interface.
///
/// You should override this if you need to perform any operations before or
/// after layouting. For instance, trimming the measurements cache.
fn layout<Message>(
&mut self,
element: &Element<'_, Message, Self>,
limits: &layout::Limits,
) -> layout::Node {
element.as_widget().layout(self, limits)
}

/// Draws the primitives recorded in the given closure in a new layer.
///
/// The layer will clip its contents to the provided `bounds`.
Expand Down
96 changes: 72 additions & 24 deletions core/src/renderer/null.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::alignment;
use crate::renderer::{self, Renderer};
use crate::text::{self, Text};
use crate::{Background, Font, Point, Rectangle, Size, Vector};
use crate::{Background, Color, Font, Pixels, Point, Rectangle, Size, Vector};

use std::borrow::Cow;

Expand Down Expand Up @@ -41,6 +42,7 @@ impl Renderer for Null {

impl text::Renderer for Null {
type Font = Font;
type Paragraph = ();

const ICON_FONT: Font = Font::DEFAULT;
const CHECKMARK_ICON: char = '0';
Expand All @@ -50,37 +52,83 @@ impl text::Renderer for Null {
Font::default()
}

fn default_size(&self) -> f32 {
16.0
fn default_size(&self) -> Pixels {
Pixels(16.0)
}

fn load_font(&mut self, _font: Cow<'static, [u8]>) {}

fn measure(
&self,
_content: &str,
_size: f32,
_line_height: text::LineHeight,
_font: Font,
_bounds: Size,
_shaping: text::Shaping,
) -> Size {
Size::new(0.0, 20.0)
fn create_paragraph(&self, _text: Text<'_, Self::Font>) -> Self::Paragraph {
}

fn hit_test(
fn resize_paragraph(
&self,
_contents: &str,
_size: f32,
_line_height: text::LineHeight,
_font: Self::Font,
_bounds: Size,
_shaping: text::Shaping,
_point: Point,
_nearest_only: bool,
) -> Option<text::Hit> {
_paragraph: &mut Self::Paragraph,
_new_bounds: Size,
) {
}

fn fill_paragraph(
&mut self,
_paragraph: &Self::Paragraph,
_position: Point,
_color: Color,
) {
}

fn fill_text(
&mut self,
_paragraph: Text<'_, Self::Font>,
_position: Point,
_color: Color,
) {
}
}

impl text::Paragraph for () {
type Font = Font;

fn content(&self) -> &str {
""
}

fn text_size(&self) -> Pixels {
Pixels(16.0)
}

fn font(&self) -> Self::Font {
Font::default()
}

fn line_height(&self) -> text::LineHeight {
text::LineHeight::default()
}

fn shaping(&self) -> text::Shaping {
text::Shaping::default()
}

fn horizontal_alignment(&self) -> alignment::Horizontal {
alignment::Horizontal::Left
}

fn vertical_alignment(&self) -> alignment::Vertical {
alignment::Vertical::Top
}

fn grapheme_position(&self, _line: usize, _index: usize) -> Option<Point> {
None
}

fn fill_text(&mut self, _text: Text<'_, Self::Font>) {}
fn bounds(&self) -> Size {
Size::ZERO
}

fn min_bounds(&self) -> Size {
Size::ZERO
}

fn hit_test(&self, _point: Point) -> Option<text::Hit> {
None
}
}
Loading
Loading