improved text and image support, support measuring sizes for taffy

This commit is contained in:
Daniel Bulant 2024-02-24 17:48:08 +01:00
parent f65588ec19
commit 389b147bfb
15 changed files with 435 additions and 128 deletions

209
Cargo.lock generated
View file

@ -313,6 +313,29 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cosmic-text"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c578f2b9abb4d5f3fbb12aba4008084d435dc6a8425c195cfe0b3594bfea0c25"
dependencies = [
"bitflags 2.4.2",
"fontdb",
"libm",
"log",
"rangemap",
"rustc-hash",
"rustybuzz 0.12.1",
"self_cell",
"swash",
"sys-locale",
"ttf-parser",
"unicode-bidi",
"unicode-linebreak",
"unicode-script",
"unicode-segmentation",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.0" version = "1.4.0"
@ -444,9 +467,9 @@ dependencies = [
[[package]] [[package]]
name = "femtovg" name = "femtovg"
version = "0.7.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3a2d0ff0df09856a5c1c89cc83863a1f0f994c55452186621bb57a01f270b3" checksum = "18ab822e58e8bc2b89840dc5dde49afe39302e129c60d39c8520200c085404a7"
dependencies = [ dependencies = [
"bitflags 2.4.2", "bitflags 2.4.2",
"fnv", "fnv",
@ -454,9 +477,10 @@ dependencies = [
"glow", "glow",
"image", "image",
"imgref", "imgref",
"log",
"lru", "lru",
"rgb", "rgb",
"rustybuzz", "rustybuzz 0.11.0",
"unicode-bidi", "unicode-bidi",
"unicode-segmentation", "unicode-segmentation",
"wasm-bindgen", "wasm-bindgen",
@ -488,6 +512,35 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "font-types"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bd7f3ea17572640b606b35df42cfb6ecdf003704b062580e59918692190b73d"
[[package]]
name = "fontconfig-parser"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a595cb550439a117696039dfc69830492058211b771a2a165379f2a1a53d84d"
dependencies = [
"roxmltree",
]
[[package]]
name = "fontdb"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
dependencies = [
"fontconfig-parser",
"log",
"memmap2",
"slotmap",
"tinyvec",
"ttf-parser",
]
[[package]] [[package]]
name = "foreign-types" name = "foreign-types"
version = "0.3.2" version = "0.3.2"
@ -660,9 +713,9 @@ dependencies = [
[[package]] [[package]]
name = "gif" name = "gif"
version = "0.12.0" version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
dependencies = [ dependencies = [
"color_quant", "color_quant",
"weezl", "weezl",
@ -687,9 +740,9 @@ dependencies = [
[[package]] [[package]]
name = "glow" name = "glow"
version = "0.12.3" version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"slotmap", "slotmap",
@ -764,9 +817,9 @@ dependencies = [
[[package]] [[package]]
name = "grid" name = "grid"
version = "0.10.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eec1c01eb1de97451ee0d60de7d81cf1e72aabefb021616027f3d1c3ec1c723c" checksum = "d196ffc1627db18a531359249b2bf8416178d84b729f3cebeb278f285fb9b58c"
[[package]] [[package]]
name = "h2" name = "h2"
@ -903,9 +956,9 @@ dependencies = [
[[package]] [[package]]
name = "image" name = "image"
version = "0.24.8" version = "0.24.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23" checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder", "byteorder",
@ -1030,6 +1083,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "libm"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]] [[package]]
name = "libredox" name = "libredox"
version = "0.0.2" version = "0.0.2"
@ -1065,9 +1124,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "lru" name = "lru"
version = "0.10.1" version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22"
[[package]] [[package]]
name = "mangades" name = "mangades"
@ -1089,10 +1148,13 @@ dependencies = [
name = "mangui" name = "mangui"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmic-text",
"femtovg", "femtovg",
"glutin", "glutin",
"glutin-winit", "glutin-winit",
"lazy_static",
"raw-window-handle 0.5.2", "raw-window-handle 0.5.2",
"swash",
"taffy", "taffy",
"weak-table", "weak-table",
"winit", "winit",
@ -1325,7 +1387,7 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7" checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7"
dependencies = [ dependencies = [
"ttf-parser 0.20.0", "ttf-parser",
] ]
[[package]] [[package]]
@ -1447,6 +1509,12 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rangemap"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "795915a3930a5d6bafd9053d37602fea3e61be2e5d4d788983a8ba9654c1c6f2"
[[package]] [[package]]
name = "raw-window-handle" name = "raw-window-handle"
version = "0.5.2" version = "0.5.2"
@ -1479,6 +1547,15 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "read-fonts"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c044ab88c43e2eae05b34a17fc13598736679fdb03d71b49fcfe114443ec8a86"
dependencies = [
"font-types",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.3.5" version = "0.3.5"
@ -1546,6 +1623,12 @@ dependencies = [
"bytemuck", "bytemuck",
] ]
[[package]]
name = "roxmltree"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
[[package]] [[package]]
name = "rusalka" name = "rusalka"
version = "0.1.0" version = "0.1.0"
@ -1566,6 +1649,12 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.31" version = "0.38.31"
@ -1590,17 +1679,34 @@ dependencies = [
[[package]] [[package]]
name = "rustybuzz" name = "rustybuzz"
version = "0.7.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a" checksum = "2ee8fe2a8461a0854a37101fe7a1b13998d0cfa987e43248e81d2a5f4570f6fa"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"bytemuck", "bytemuck",
"smallvec", "smallvec",
"ttf-parser 0.18.1", "ttf-parser",
"unicode-bidi-mirroring", "unicode-bidi-mirroring",
"unicode-ccc", "unicode-ccc",
"unicode-general-category", "unicode-properties",
"unicode-script",
]
[[package]]
name = "rustybuzz"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0ae5692c5beaad6a9e22830deeed7874eae8a4e3ba4076fb48e12c56856222c"
dependencies = [
"bitflags 2.4.2",
"bytemuck",
"libm",
"smallvec",
"ttf-parser",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-properties",
"unicode-script", "unicode-script",
] ]
@ -1676,6 +1782,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "self_cell"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.197" version = "1.0.197"
@ -1817,6 +1929,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
[[package]]
name = "swash"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d06ff4664af8923625604261c645f5c4cc610cc83c84bec74b50d76237089de7"
dependencies = [
"read-fonts",
"yazi",
"zeno",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.50" version = "2.0.50"
@ -1834,6 +1957,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sys-locale"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"
@ -1857,13 +1989,14 @@ dependencies = [
[[package]] [[package]]
name = "taffy" name = "taffy"
version = "0.3.18" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c2287b6d7f721ada4cddf61ade5e760b2c6207df041cac9bfaa192897362fd3" checksum = "fddbee94e20bc4612dcb789953324236eebd4fc6a08c650ccbf7f615e59a0d6a"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"grid", "grid",
"num-traits", "num-traits",
"serde",
"slotmap", "slotmap",
] ]
@ -2052,12 +2185,6 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "ttf-parser"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
[[package]] [[package]]
name = "ttf-parser" name = "ttf-parser"
version = "0.20.0" version = "0.20.0"
@ -2082,18 +2209,18 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
[[package]]
name = "unicode-general-category"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-linebreak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
version = "0.1.23" version = "0.1.23"
@ -2103,6 +2230,12 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "unicode-properties"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
[[package]] [[package]]
name = "unicode-script" name = "unicode-script"
version = "0.5.6" version = "0.5.6"
@ -2730,6 +2863,18 @@ version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
[[package]]
name = "yazi"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
[[package]]
name = "zeno"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.32" version = "0.7.32"

View file

@ -33,8 +33,8 @@ impl Component for DemoComponent {
style: Style { style: Style {
layout: mangui::nodes::TaffyStyle { layout: mangui::nodes::TaffyStyle {
min_size: Size { min_size: Size {
width: mangui::taffy::style::Dimension::Points( if **test.lock().unwrap() { 50. } else { 100. }), width: mangui::taffy::style::Dimension::Length( if **test.lock().unwrap() { 50. } else { 100. }),
height: mangui::taffy::style::Dimension::Points(100.) height: mangui::taffy::style::Dimension::Length(100.)
}, },
..Default::default() ..Default::default()
}, },

View file

@ -1,6 +1,8 @@
use rusalka_macro::make_component; use rusalka_macro::make_component;
use std::default::Default; use std::default::Default;
use mangui::{femtovg::{ImageFlags, Color, Paint}, cosmic_text::Metrics, nodes::{layout::Layout, Style}, nodes::text::Text, nodes::image::Image, taffy::prelude::Size}; use mangui::{femtovg::{ImageFlags, Color, Paint}, cosmic_text::Metrics, nodes::{layout::Layout, Style}, nodes::text::Text, nodes::image::Image, taffy::prelude::Size};
use mangui::nodes::TaffyStyle;
use mangui::taffy::Display::Block;
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes}; use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes};
@ -28,34 +30,32 @@ make_component!(
radius: if $test_ { attrs.radius } else { 0. }, radius: if $test_ { attrs.radius } else { 0. },
..Default::default() ..Default::default()
} }
@image { @layout {
style: Style { @image {
layout: mangui::nodes::TaffyStyle { style: Style {
min_size: Size { layout: TaffyStyle {
width: mangui::taffy::style::Dimension::Points(width), min_size: Size {
height: mangui::taffy::style::Dimension::Points(height) width: mangui::taffy::style::Dimension::Length(width),
height: mangui::taffy::style::Dimension::Length(height)
},
..Default::default()
}, },
..Default::default() ..Default::default()
}, },
image: mangui::nodes::image::ImageLoad::LoadFile(imgpath, imgflags),
radius: 5.,
..Default::default() ..Default::default()
}, }
image: mangui::nodes::image::ImageLoad::LoadFile(imgpath, imgflags), @text {
width, text: String::from("Hello, World!"),
height, metrics: Metrics::new(20., 25.),
radius: 5., paint: Paint::color(Color::rgb(0, 255, 0)),
events: Default::default(), ..Default::default()
parent: None }
}
@text {
text: String::from("Hello, World!"),
metrics: Metrics::new(20., 25.),
paint: Paint::color(Color::rgb(0, 255, 0)),
style: Style { style: Style {
layout: mangui::nodes::TaffyStyle { layout: TaffyStyle {
min_size: Size { display: Block,
width: mangui::taffy::style::Dimension::Points(200.),
height: mangui::taffy::style::Dimension::Points(40.)
},
..Default::default() ..Default::default()
}, },
..Default::default() ..Default::default()

View file

@ -4,6 +4,7 @@ use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{sel
mod component_demo; mod component_demo;
mod component_demo_syntax; mod component_demo_syntax;
mod anilist;
use rusalka::component::Component; use rusalka::component::Component;
@ -15,11 +16,10 @@ fn main() {
root.style.layout.flex_direction = taffy::style::FlexDirection::Row; root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
let right_node = Arc::new(RwLock::new(nodes::primitives::Rectangle { let right_node = Arc::new(RwLock::new(nodes::primitives::Rectangle {
style: Style { style: Style {
overflow: nodes::Overflow::Visible,
layout: TaffyStyle { layout: TaffyStyle {
min_size: Size { min_size: Size {
width: Dimension::Points(50.), width: Dimension::Length(50.),
height: Dimension::Points(100.) height: Dimension::Length(100.)
}, },
..Default::default() ..Default::default()
}, },

View file

@ -791,6 +791,9 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let num_offset = index % 32; let num_offset = index % 32;
*keys.get_mut(array_offset).unwrap() |= 1 << num_offset; *keys.get_mut(array_offset).unwrap() |= 1 << num_offset;
} }
if keys.iter().all(|x| *x == 0) {
continue 'block;
}
update_stream.extend(TokenStream::from(quote!(if))); update_stream.extend(TokenStream::from(quote!(if)));
let mut i = 0; let mut i = 0;

View file

@ -4,7 +4,7 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}}; use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}};
use crate::{component::Component, SharedComponent, WeakSharedComponent}; use crate::{component::Component, WeakSharedComponent};
use super::{insert, detach}; use super::{insert, detach};
@ -43,8 +43,8 @@ impl Component for Rectangle {
style: Style { style: Style {
layout: mangui::nodes::TaffyStyle { layout: mangui::nodes::TaffyStyle {
min_size: Size { min_size: Size {
width: mangui::taffy::style::Dimension::Points(50.), width: mangui::taffy::style::Dimension::Length(50.),
height: mangui::taffy::style::Dimension::Points(100.) height: mangui::taffy::style::Dimension::Length(100.)
}, },
..Default::default() ..Default::default()
}, },

View file

@ -6,10 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
femtovg = "0.7.1" femtovg = "0.8.2"
glutin = "0.31.0" glutin = "0.31.3"
raw-window-handle = "0.5.0" raw-window-handle = "0.5.0"
winit = { version = "0.29.2" } winit = { version = "0.29.10" }
glutin-winit = "0.4.2" glutin-winit = "0.4.2"
taffy = "0.3.16" taffy = "0.4.0"
weak-table = "0.3.2" weak-table = "0.3.2"
cosmic-text = "0.11.2"
swash = "0.1.12"
lazy_static = "1.4.0"

View file

@ -185,8 +185,8 @@ impl Into<(f32, f32)> for Location {
impl Into<Size<Dimension>> for Location { impl Into<Size<Dimension>> for Location {
fn into(self) -> Size<Dimension> { fn into(self) -> Size<Dimension> {
Size { Size {
width: Dimension::Points(self.x as f32), width: Dimension::Length(self.x as f32),
height: Dimension::Points(self.y as f32) height: Dimension::Length(self.y as f32)
} }
} }
} }

View file

@ -26,10 +26,9 @@ use glutin::{
surface::{SurfaceAttributesBuilder, WindowSurface}, surface::{SurfaceAttributesBuilder, WindowSurface},
}; };
use taffy::geometry::Size; use taffy::geometry::Size;
use taffy::style_helpers::TaffyMaxContent; use taffy::{style::AvailableSpace, TaffyTree};
use taffy::Taffy;
use weak_table::PtrWeakKeyHashMap; use weak_table::PtrWeakKeyHashMap;
use crate::nodes::{layout_recursively, Node, render_recursively, RenderContext}; use crate::nodes::{update_taffynode_children, MeasureContext, Node, render_recursively, RenderContext, prepare_render_recursively};
pub mod nodes; pub mod nodes;
pub mod events; pub mod events;
@ -41,7 +40,7 @@ pub type CurrentRenderer = OpenGl;
pub type SharedNode = Arc<RwLock<dyn Node>>; pub type SharedNode = Arc<RwLock<dyn Node>>;
type WeakNode = Weak<RwLock<dyn Node>>; type WeakNode = Weak<RwLock<dyn Node>>;
type NodePtr = Option<Vec<WeakNode>>; type NodePtr = Option<Vec<WeakNode>>;
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::node::Node>; type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::tree::NodeId>;
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref FONT_SYSTEM: Mutex<FontSystem> = Mutex::new(FontSystem::new()); pub static ref FONT_SYSTEM: Mutex<FontSystem> = Mutex::new(FontSystem::new());
@ -77,7 +76,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
let canvas = Canvas::new(renderer).expect("Cannot create canvas"); let canvas = Canvas::new(renderer).expect("Cannot create canvas");
let mut taffy = Taffy::new(); let mut taffy = TaffyTree::new();
let mut taffy_map = NodeLayoutMap::new(); let mut taffy_map = NodeLayoutMap::new();
{ {
let clonned = entry.root.clone(); let clonned = entry.root.clone();
@ -89,13 +88,15 @@ pub fn run_event_loop(entry: MainEntry) -> () {
taffy_map.insert(entry.root.clone(), taffy_root_node); taffy_map.insert(entry.root.clone(), taffy_root_node);
} }
let size = window.inner_size();
let mut context = RenderContext { let mut context = RenderContext {
canvas, canvas,
node_layout: taffy_map, node_layout: taffy_map,
taffy, taffy,
mouse: None, mouse: None,
keyboard_focus: None, keyboard_focus: None,
scale_factor: window.scale_factor() as f32 scale_factor: window.scale_factor() as f32,
window_size: Size { width: size.width as f32, height: size.height as f32 }
}; };
let root = entry.root.clone(); let root = entry.root.clone();
@ -250,7 +251,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
}, },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
if should_recompute { if should_recompute {
layout_recursively(&root, &mut context); update_taffynode_children(&root, &mut context);
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>(); let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
context.node_layout.remove_expired(); context.node_layout.remove_expired();
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>(); let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
@ -260,12 +261,33 @@ pub fn run_event_loop(entry: MainEntry) -> () {
dbg!("Removed node", src_node); dbg!("Removed node", src_node);
} }
} }
prepare_render_recursively(&root, &mut context);
for (node, taffy_node) in context.node_layout.iter() { for (node, taffy_node) in context.node_layout.iter() {
let node = node.read().unwrap(); let node = node.read().unwrap();
let node_style = node.style(); let node_style = node.style();
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap(); context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
} }
context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap(); let size = window.inner_size();
let size = Size { width: AvailableSpace::Definite(size.width as f32), height: AvailableSpace::Definite(size.height as f32) };
let RenderContext { taffy, node_layout, canvas, scale_factor, .. } = &mut context;
let mut measure_context = MeasureContext { canvas, scale_factor: *scale_factor };
taffy.compute_layout_with_measure(
*node_layout.get(&root).unwrap(),
size,
|known_dimensions, available_space, _node_id, node_context| {
match node_context {
Some(node) => {
match node.upgrade() {
Some(node) => {
node.write().unwrap().measure(&mut measure_context, known_dimensions, available_space)
},
None => Size::ZERO
}
},
None => Size::ZERO
}
},
).unwrap();
should_recompute = false; should_recompute = false;
// Additional optimizations could be done here // Additional optimizations could be done here
// - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty) // - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty)
@ -275,7 +297,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
// could perhaps be a significant boost regarding memory usage (and performance) during large layout changes // could perhaps be a significant boost regarding memory usage (and performance) during large layout changes
// dbg!("recomputed"); // dbg!("recomputed");
} }
// dbg!(&root); // Clear the render queue
while let Ok(_) = entry.render.try_recv() {} while let Ok(_) = entry.render.try_recv() {}
render(&buffer_context, &surface, &window, &mut context, &root); render(&buffer_context, &surface, &window, &mut context, &root);
} }

View file

@ -1,9 +1,11 @@
use std::{fmt::Debug, mem, path::PathBuf}; use std::{fmt::Debug, mem, path::PathBuf};
use std::sync::Mutex;
use femtovg::{Color, ErrorKind, ImageFlags, ImageId, Paint, Path}; use femtovg::{Color, ErrorKind, ImageFlags, ImageId, Paint, Path};
use taffy::{AvailableSpace, Size};
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode}; use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode};
use super::{Node, NodeChildren, Style}; use super::{MeasureContext, Node, NodeChildren, RenderContext, Style};
#[derive(Debug)] #[derive(Debug, Default)]
/// Status of the image - when rendering, image node attempts to load the image and sets this status accordingly. /// Status of the image - when rendering, image node attempts to load the image and sets this status accordingly.
/// Changes this if you want to change the image. If the previous status was loaded, free the image. /// Changes this if you want to change the image. If the previous status was loaded, free the image.
/// In case the loading fails, image load status changes to Error and the node doesn't render. /// In case the loading fails, image load status changes to Error and the node doesn't render.
@ -11,27 +13,48 @@ pub enum ImageLoad {
LoadFile(PathBuf, ImageFlags), LoadFile(PathBuf, ImageFlags),
// LoadArray(&[u8]), // LoadArray(&[u8]),
LoadVec(Vec<u8>, ImageFlags), LoadVec(Vec<u8>, ImageFlags),
Loaded(ImageId), Loaded(ImageHandle),
Error(ErrorKind) Error(ErrorKind),
#[default]
Empty
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ImageHandle {
image: ImageId
}
impl ImageHandle {
fn new(image: ImageId) -> ImageHandle {
ImageHandle {
image
}
}
}
impl Drop for ImageHandle {
fn drop(&mut self) {
IMAGES_TO_UNLOAD.lock().unwrap().push(self.image);
}
}
#[derive(Debug, Default)]
/// Image node. /// Image node.
/// Sadly doesn't implement `Default` because of the `ImageLoad` enum. /// Sadly doesn't implement `Default` because of the `ImageLoad` enum.
pub struct Image { pub struct Image {
pub style: Style, pub style: Style,
/// The image to be rendered. /// The image to be rendered.
pub image: ImageLoad, pub image: ImageLoad,
/// Image width - note that you also have to set the style accordingly for it to render correctly, this is more about scaling the image
pub width: f32,
/// Image height - note that you also have to set the style accordingly for it to render correctly, this is more about scaling the image
pub height: f32,
/// Border radius /// Border radius
pub radius: f32, pub radius: f32,
pub events: EventHandlerDatabase, pub events: EventHandlerDatabase,
pub parent: Option<WeakNode> pub parent: Option<WeakNode>
} }
lazy_static::lazy_static! {
pub static ref IMAGES_TO_UNLOAD: Mutex<Vec<ImageId>> = Mutex::new(Vec::new());
}
impl Node for Image { impl Node for Image {
fn style(&self) -> &Style { fn style(&self) -> &Style {
&self.style &self.style
@ -41,14 +64,14 @@ impl Node for Image {
None None
} }
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) { fn prepare_render(&mut self, context: &mut RenderContext) {
match &self.image { match &self.image {
ImageLoad::LoadFile(_, _) => { ImageLoad::LoadFile(_, _) => {
let image = mem::replace(&mut self.image, ImageLoad::Error(ErrorKind::UnknownError)); let image = mem::replace(&mut self.image, ImageLoad::Error(ErrorKind::UnknownError));
if let ImageLoad::LoadFile(path, flags) = image { if let ImageLoad::LoadFile(path, flags) = image {
match context.canvas.load_image_file(path, flags) { match context.canvas.load_image_file(path, flags) {
Ok(image) => { Ok(image) => {
self.image = ImageLoad::Loaded(image); self.image = ImageLoad::Loaded(ImageHandle::new(image));
}, },
Err(e) => { Err(e) => {
self.image = ImageLoad::Error(e); self.image = ImageLoad::Error(e);
@ -59,7 +82,7 @@ impl Node for Image {
ImageLoad::LoadVec(data, flags) => { ImageLoad::LoadVec(data, flags) => {
match context.canvas.load_image_mem(data, *flags) { match context.canvas.load_image_mem(data, *flags) {
Ok(image) => { Ok(image) => {
self.image = ImageLoad::Loaded(image); self.image = ImageLoad::Loaded(ImageHandle::new(image));
}, },
Err(e) => { Err(e) => {
self.image = ImageLoad::Error(e); self.image = ImageLoad::Error(e);
@ -68,6 +91,9 @@ impl Node for Image {
}, },
_ => {} _ => {}
} }
}
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
let mut path = Path::new(); let mut path = Path::new();
path.rounded_rect( path.rounded_rect(
0., 0.,
@ -80,13 +106,37 @@ impl Node for Image {
ImageLoad::Loaded(image) => { ImageLoad::Loaded(image) => {
context.canvas.fill_path( context.canvas.fill_path(
&path, &path,
&Paint::image(*image, 0., 0., self.width, self.height, 0., 1.) &Paint::image(image.image, 0., 0., layout.size.width, layout.size.height, 0., 1.)
); );
}, },
ImageLoad::Error(_) => { ImageLoad::Error(_) => {
context.canvas.fill_path(&path, &Paint::color(Color::rgb(255, 0, 0))) context.canvas.fill_path(&path, &Paint::color(Color::rgb(255, 0, 0)))
}, },
_ => unreachable!("We just loaded the image before, so it's either loaded or errored out.") _ => {
// this shouldn't happen as the image should be loaded earlier during the render pass,
// but someone can still change the image in another thread
}
}
}
fn measure(&mut self, context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, _available_space: Size<AvailableSpace>) -> Size<f32> {
match &self.image {
ImageLoad::Loaded(image) => {
match context.canvas.image_size(image.image) {
Ok((img_width, img_height)) => {
let img_width = img_width as f32;
let img_height = img_height as f32;
match (known_dimensions.width, known_dimensions.height) {
(Some(width), Some(height)) => Size { width, height },
(Some(width), None) => Size { width, height: (width / img_width) * img_height },
(None, Some(height)) => Size { width: (height / img_height) * img_width, height },
(None, None) => Size { width: img_width, height: img_height },
}
},
_ => Size::ZERO
}
},
_ => Size::ZERO
} }
} }

View file

@ -39,8 +39,8 @@ impl Node for Layout {
Some(&self.children) Some(&self.children)
} }
fn resize(&mut self, width: f32, height: f32) { fn resize(&mut self, width: f32, height: f32) {
self.style.layout.size.width = Dimension::Points(width); self.style.layout.size.width = Dimension::Length(width);
self.style.layout.size.height = Dimension::Points(height); self.style.layout.size.height = Dimension::Length(height);
} }
fn add_child_at(&mut self, child: crate::SharedNode, index: usize) -> Result<(), super::ChildAddError> { fn add_child_at(&mut self, child: crate::SharedNode, index: usize) -> Result<(), super::ChildAddError> {

View file

@ -7,22 +7,27 @@ pub mod text_render_cache;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
use femtovg::{Canvas, Color}; use femtovg::{Canvas, Color};
use taffy::layout::Layout;
use taffy::Taffy;
use crate::events::Location; use crate::events::Location;
use crate::events::handler::InnerEventHandlerDataset; use crate::events::handler::InnerEventHandlerDataset;
use crate::{NodeLayoutMap, NodePtr, CurrentRenderer, SharedNode, WeakNode}; use crate::{NodeLayoutMap, NodePtr, CurrentRenderer, SharedNode, WeakNode};
pub use taffy::style::Style as TaffyStyle; pub use taffy::style::Style as TaffyStyle;
use taffy::{Layout, Overflow, Size, TaffyTree};
pub type CanvasRenderer = Canvas<CurrentRenderer>; pub type CanvasRenderer = Canvas<CurrentRenderer>;
pub struct RenderContext { pub struct RenderContext {
pub canvas: CanvasRenderer, pub canvas: CanvasRenderer,
pub node_layout: NodeLayoutMap, pub node_layout: NodeLayoutMap,
pub taffy: Taffy, pub taffy: TaffyTree<WeakNode>,
pub mouse: NodePtr, pub mouse: NodePtr,
pub keyboard_focus: NodePtr, pub keyboard_focus: NodePtr,
pub scale_factor: f32,
pub window_size: Size<f32>
}
pub struct MeasureContext<'a> {
pub canvas: &'a mut CanvasRenderer,
pub scale_factor: f32 pub scale_factor: f32
} }
@ -39,18 +44,6 @@ impl RenderContext {
} }
} }
#[derive(Copy, Clone, Default, Debug)]
#[non_exhaustive]
pub enum Overflow {
#[default]
/// Content is not clipped and may be rendered outside the element's box
Visible,
/// Clips the content at the border of the element
Hidden,
// tbd :)
// Scroll,
// Auto
}
#[derive(Copy, Clone, Default, Debug)] #[derive(Copy, Clone, Default, Debug)]
pub enum Cursor { pub enum Cursor {
#[default] #[default]
@ -59,7 +52,6 @@ pub enum Cursor {
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
pub struct Style { pub struct Style {
pub layout: TaffyStyle, pub layout: TaffyStyle,
pub overflow: Overflow,
pub cursor: Cursor pub cursor: Cursor
} }
@ -95,9 +87,26 @@ pub enum ChildAddError {
/// # Events /// # Events
/// ///
/// If you need to handle events, implement [`Node::event_handlers`]. /// If you need to handle events, implement [`Node::event_handlers`].
///
/// # Function call order
///
/// Read-only functions are called in any order (style, children, event_handlers, measure).
///
/// `resize` is called independently of the rendering process, but not concurrently with it. The render process is single-threaded.
///
/// During rendering, the order is following:
///
/// - parents are changed ([`Node::set_parent`]) to new state according to read-only functions
/// - [`Node::prepare_render`] is called on each node
/// - [`Node::style`] is read
/// - [`Node::measure`] is called on some nodes (depends on taffy); can be called multiple times
/// - nodes are rendered, i.e. on each node, starting from the root node, the following is called:
/// - [`Node::render_pre_children`] is called
/// - children are rendered
/// - [`Node::render_post_children`] is called
pub trait Node: Debug { pub trait Node: Debug {
/// Return style. /// Return style.
/// ///insert
/// If you're using [`Style`] in your struct directly, your implementation can be as simple as: /// If you're using [`Style`] in your struct directly, your implementation can be as simple as:
/// ```rust /// ```rust
/// fn style(&self) -> &Style { &self.style } /// fn style(&self) -> &Style { &self.style }
@ -219,6 +228,22 @@ pub trait Node: Debug {
None None
} }
/// Called on each redraw. Use this to prepare for rendering. Called before any layouting or rendering happens.
/// Order between nodes is not guaranteed.
fn prepare_render(&mut self, _context: &mut RenderContext) {}
/// Called before rendering the node to measure it's size.
/// The calling of this method is managed by taffy, and as such:
/// - It may be called multiple times (with same or different arguments) during the same render pass
/// - It may not be called at all
/// - order between nodes is not guaranteed
///
/// If you need to change self during layouting, use [`Node::prepare_render`] to do so.
/// You're getting &mut self here to support things like cosmic text that require changing text data to measure it.
fn measure(&mut self, _context: &mut MeasureContext, _known_dimensions: Size<Option<f32>>, _available_space: Size<taffy::AvailableSpace>) -> Size<f32> {
Size::ZERO
}
/// Returns true if the node has the given child /// Returns true if the node has the given child
/// Returns false if there are no children (or if the node does not support children) /// Returns false if there are no children (or if the node does not support children)
fn has_child(&self, child: &SharedNode) -> Option<usize> { fn has_child(&self, child: &SharedNode) -> Option<usize> {
@ -295,12 +320,15 @@ pub(crate) fn get_element_at(node: &SharedNode, context: &RenderContext, locatio
} }
} }
pub(crate) fn layout_recursively(node: &SharedNode, context: &mut RenderContext) -> taffy::node::Node { pub(crate) fn update_taffynode_children(node: &SharedNode, context: &mut RenderContext) -> taffy::tree::NodeId {
let taffy_node = context.node_layout.get(node); let taffy_node = context.node_layout.get(node);
let taffy_node = match taffy_node { let taffy_node = match taffy_node {
Some(taffy_node) => taffy_node, Some(taffy_node) => taffy_node,
None => { None => {
let taffy_node = context.taffy.new_leaf(node.read().unwrap().style().layout.to_owned()).unwrap(); let taffy_node = context.taffy.new_leaf_with_context(
node.read().unwrap().style().layout.to_owned(),
Arc::downgrade(node)
).unwrap();
context.node_layout.insert(node.clone(), taffy_node); context.node_layout.insert(node.clone(), taffy_node);
context.node_layout.get(node).unwrap() context.node_layout.get(node).unwrap()
} }
@ -313,7 +341,7 @@ pub(crate) fn layout_recursively(node: &SharedNode, context: &mut RenderContext)
Some(children) => { Some(children) => {
let mut t_children = Vec::with_capacity(children.len()); let mut t_children = Vec::with_capacity(children.len());
for child in children { for child in children {
t_children.push(layout_recursively(child, context).to_owned()); t_children.push(update_taffynode_children(child, context).to_owned());
child.write().unwrap().set_parent(Some(Arc::downgrade(node))); child.write().unwrap().set_parent(Some(Arc::downgrade(node)));
} }
context.taffy.set_children(taffy_node, t_children.as_slice()).unwrap(); context.taffy.set_children(taffy_node, t_children.as_slice()).unwrap();
@ -331,16 +359,15 @@ pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext)
let sself = node.clone(); let sself = node.clone();
context.canvas.save(); context.canvas.save();
context.canvas.translate(layout.location.x, layout.location.y); context.canvas.translate(layout.location.x, layout.location.y);
match styles.overflow { let clip_width = matches!(styles.layout.overflow.x, Overflow::Hidden | Overflow::Clip);
Overflow::Visible => {}, let clip_height = matches!(styles.layout.overflow.y, Overflow::Hidden | Overflow::Clip);
Overflow::Hidden => { if clip_width || clip_height {
context.canvas.scissor( context.canvas.scissor(
0., 0.,
0., 0.,
layout.size.width, if clip_width { layout.size.width } else { f32::INFINITY },
layout.size.height, if clip_height { layout.size.height } else { f32::INFINITY },
); );
}
} }
drop(read_node); drop(read_node);
sself.write().unwrap().render_pre_children(context, layout); sself.write().unwrap().render_pre_children(context, layout);
@ -351,4 +378,14 @@ pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext)
} }
sself.write().unwrap().render_post_children(context, layout); sself.write().unwrap().render_post_children(context, layout);
context.canvas.restore(); context.canvas.restore();
}
pub(crate) fn prepare_render_recursively(node: &SharedNode, context: &mut RenderContext) {
let mut write_node = node.write().unwrap();
write_node.prepare_render(context);
if let Some(children) = write_node.children() {
for child in children {
prepare_render_recursively(child, context);
}
}
} }

View file

@ -1,5 +1,5 @@
use femtovg::{Color, Paint, Path}; use femtovg::{Color, Paint, Path};
use taffy::layout::Layout; use taffy::Layout;
use crate::{nodes::{Node, NodeChildren, RenderContext, Style}, events::handler::EventHandlerDatabase, WeakNode, SharedNode}; use crate::{nodes::{Node, NodeChildren, RenderContext, Style}, events::handler::EventHandlerDatabase, WeakNode, SharedNode};
#[derive(Default, Debug)] #[derive(Default, Debug)]

View file

@ -1,8 +1,9 @@
use std::fmt::Debug; use std::fmt::Debug;
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM}; use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM};
use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style}; use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style, MeasureContext, RenderContext};
use cosmic_text::{Attrs, Buffer, Metrics, Shaping}; use cosmic_text::{Attrs, Buffer, Metrics, Shaping};
use femtovg::Paint; use femtovg::{Color, Paint, Path};
use taffy::{AvailableSpace, Size};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Text { pub struct Text {
@ -24,22 +25,66 @@ impl Node for Text {
None None
} }
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) { fn prepare_render(&mut self, _context: &mut RenderContext) {
if let None = self.buffer { if let None = self.buffer {
self.buffer = Some(Buffer::new(&mut FONT_SYSTEM.lock().unwrap(), self.metrics)); self.buffer = Some(Buffer::new(&mut FONT_SYSTEM.lock().unwrap(), self.metrics));
} }
let buf = self.buffer.as_mut().unwrap(); let buf = self.buffer.as_mut().unwrap();
let mut font = FONT_SYSTEM.lock().unwrap(); let mut font = FONT_SYSTEM.lock().unwrap();
buf.set_text(&mut font, &self.text, Attrs::new(), Shaping::Advanced); buf.set_text(&mut font, &self.text, Attrs::new(), Shaping::Advanced);
}
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
// this can crash, but it should crash earlier during measure -> see the comment there.
let buf = self.buffer.as_mut().unwrap();
let mut font = FONT_SYSTEM.lock().unwrap();
buf.set_size(&mut font, layout.size.width, layout.size.height); buf.set_size(&mut font, layout.size.width, layout.size.height);
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor)); buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
// fill_to_cmds requires FONT_SYSTEM lock.
drop(font); drop(font);
let mut path = Path::new();
path.rounded_rect(
0.,
0.,
layout.size.width,
layout.size.height,
0.
);
context.canvas.fill_path(
&path,
&Paint::color(Color::rgb(255, 0, 0))
);
let cmds = RENDER_CACHE.lock().unwrap() let cmds = RENDER_CACHE.lock().unwrap()
.fill_to_cmds(&mut context.canvas, buf, (0.0, 0.0), context.scale_factor) .fill_to_cmds(&mut context.canvas, buf, (0.0, 0.0), context.scale_factor)
.unwrap(); .unwrap();
context.canvas.draw_glyph_commands(cmds, &self.paint, 1.0); context.canvas.draw_glyph_commands(cmds, &self.paint, 1.0);
} }
fn measure(&mut self, _context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
let width_constraint = known_dimensions.width.unwrap_or(match available_space.width {
AvailableSpace::MinContent => 0.0,
AvailableSpace::MaxContent => f32::INFINITY,
AvailableSpace::Definite(width) => width,
});
// yes, this can crash if someone removes `buffer` during render from another thread.
// though they're asking for it, so let them crash.
let buf = self.buffer.as_mut().unwrap();
buf.set_size(&mut FONT_SYSTEM.lock().unwrap(), width_constraint, f32::INFINITY);
// Compute layout
buf.shape_until_scroll(&mut FONT_SYSTEM.lock().unwrap(), false);
// Determine measured size of text
let (width, total_lines) = buf
.layout_runs()
.fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
let height = total_lines as f32 * buf.metrics().line_height;
// fixes flickering of text on devices with non-integer scale factors due to loss of precision
let width = width + 0.5;
Size { width, height }
}
fn event_handlers(&self) -> Option<crate::events::handler::InnerEventHandlerDataset> { fn event_handlers(&self) -> Option<crate::events::handler::InnerEventHandlerDataset> {
Some(self.events.handlers.clone()) Some(self.events.handlers.clone())
} }

View file

@ -49,6 +49,8 @@ lazy_static::lazy_static! {
} }
impl RenderCache { impl RenderCache {
/// Generates draw commands from cosmic text buffer.
/// Note that this requires a lock on FONT_SYSTEM.
pub(crate) fn fill_to_cmds( pub(crate) fn fill_to_cmds(
&mut self, &mut self,
canvas: &mut CanvasRenderer, canvas: &mut CanvasRenderer,