diff --git a/CHANGELOG.md b/CHANGELOG.md index d3ae70ea..ead51559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,13 +29,14 @@ This release has an [MSRV] of 1.82. ### Fixed -#### Fontique - -- Font family name aliases (secondary names for font families, often in another language) not being registered. ([#380][] by [@valadaptive][]) - #### Parley - Selection extension moves the focus to the side being extended. ([#385][] by [@kekelp][]) +- Ranged builder default style not respecting `scale`. ([#368][] by [@xStrom][]) + +#### Fontique + +- Font family name aliases (secondary names for font families, often in another language) not being registered. ([#380][] by [@valadaptive][]) ## [0.5.0] - 2025-06-01 @@ -308,6 +309,7 @@ This release has an [MSRV][] of 1.70. [#348]: https://github.com/linebender/parley/pull/348 [#353]: https://github.com/linebender/parley/pull/353 [#362]: https://github.com/linebender/parley/pull/362 +[#368]: https://github.com/linebender/parley/pull/368 [#369]: https://github.com/linebender/parley/pull/369 [#378]: https://github.com/linebender/parley/pull/378 [#380]: https://github.com/linebender/parley/pull/380 diff --git a/examples/swash_render/src/main.rs b/examples/swash_render/src/main.rs index d78d0199..82aef015 100644 --- a/examples/swash_render/src/main.rs +++ b/examples/swash_render/src/main.rs @@ -133,7 +133,7 @@ fn main() { let (layout, _text): (Layout, String) = builder.build(); layout } else { - // RANGE BUILDER + // RANGED BUILDER // ============ // Creates a RangedBuilder diff --git a/parley/src/context.rs b/parley/src/context.rs index dc9898b2..2d5c79b8 100644 --- a/parley/src/context.rs +++ b/parley/src/context.rs @@ -87,7 +87,10 @@ impl LayoutContext { quantize: bool, ) -> RangedBuilder<'a, B> { self.begin(); - self.ranged_style_builder.begin(text.len()); + + let resolved_root_style = self.resolve_style_set(fcx, scale, &TextStyle::default()); + self.ranged_style_builder + .begin(resolved_root_style, text.len()); fcx.source_cache.prune(128, false); @@ -123,11 +126,11 @@ impl LayoutContext { fcx: &'a mut FontContext, scale: f32, quantize: bool, - raw_style: &TextStyle<'_, B>, + root_style: &TextStyle<'_, B>, ) -> TreeBuilder<'a, B> { self.begin(); - let resolved_root_style = self.resolve_style_set(fcx, scale, raw_style); + let resolved_root_style = self.resolve_style_set(fcx, scale, root_style); self.tree_style_builder.begin(resolved_root_style); fcx.source_cache.prune(128, false); diff --git a/parley/src/layout/editor.rs b/parley/src/layout/editor.rs index 820102cb..84c9831a 100644 --- a/parley/src/layout/editor.rs +++ b/parley/src/layout/editor.rs @@ -9,7 +9,6 @@ use crate::{ Affinity, Alignment, AlignmentOptions, Layout, cursor::{Cursor, Selection}, }, - resolve::ResolvedStyle, style::Brush, }; use alloc::{borrow::ToOwned, string::String, vec::Vec}; @@ -114,6 +113,7 @@ where /// Whether the cursor should be shown. The IME can request to hide the cursor. show_cursor: bool, width: Option, + font_size: f32, scale: f32, quantize: bool, // Simple tracking of when the layout needs to be updated @@ -146,6 +146,7 @@ where compose: None, show_cursor: true, width: None, + font_size, scale: 1.0, quantize: true, layout_dirty: true, @@ -925,7 +926,7 @@ where let font_size = downstream .or(upstream) .map(|cluster| cluster.run().font_size()) - .unwrap_or(ResolvedStyle::::default().font_size); + .unwrap_or(self.font_size * self.scale); // Using 0.6 as an estimate of the average advance let inflate = 3. * 0.6 * font_size as f64; let editor_width = self.width.map(f64::from).unwrap_or(f64::INFINITY); diff --git a/parley/src/resolve/mod.rs b/parley/src/resolve/mod.rs index 0270b854..8373ea00 100644 --- a/parley/src/resolve/mod.rs +++ b/parley/src/resolve/mod.rs @@ -377,7 +377,7 @@ pub(crate) enum ResolvedProperty { } /// Flattened group of style properties. -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug, Default)] pub(crate) struct ResolvedStyle { /// Font stack. pub(crate) font_stack: Resolved, @@ -413,29 +413,6 @@ pub(crate) struct ResolvedStyle { pub(crate) overflow_wrap: OverflowWrap, } -impl Default for ResolvedStyle { - fn default() -> Self { - Self { - font_stack: Resolved::default(), - font_size: 16., - font_width: Default::default(), - font_style: Default::default(), - font_weight: Default::default(), - font_variations: Default::default(), - font_features: Default::default(), - locale: None, - brush: Default::default(), - underline: Default::default(), - strikethrough: Default::default(), - line_height: Default::default(), - word_spacing: 0., - letter_spacing: 0., - word_break: Default::default(), - overflow_wrap: Default::default(), - } - } -} - impl ResolvedStyle { /// Applies the specified property to this style. pub(crate) fn apply(&mut self, property: ResolvedProperty) { diff --git a/parley/src/resolve/range.rs b/parley/src/resolve/range.rs index 658273d5..7e4c6966 100644 --- a/parley/src/resolve/range.rs +++ b/parley/src/resolve/range.rs @@ -13,7 +13,7 @@ use core::ops::{Bound, Range, RangeBounds}; #[derive(Clone)] pub(crate) struct RangedStyleBuilder { properties: Vec>, - default_style: ResolvedStyle, + root_style: ResolvedStyle, len: usize, } @@ -21,31 +21,32 @@ impl Default for RangedStyleBuilder { fn default() -> Self { Self { properties: vec![], - default_style: Default::default(), + root_style: ResolvedStyle::default(), len: !0, } } } impl RangedStyleBuilder { - /// Prepares the builder for accepting ranged properties for text of the - /// specified length. - pub(crate) fn begin(&mut self, len: usize) { + /// Prepares the builder for accepting ranged properties for text of the specified length. + /// + /// The provided `root_style` is the default style applied to all text unless overridden. + pub(crate) fn begin(&mut self, root_style: ResolvedStyle, len: usize) { self.properties.clear(); - self.default_style = ResolvedStyle::default(); + self.root_style = root_style; self.len = len; } - /// Pushes a property that covers the full range of text. + /// Change a property of the root style, which covers the full range of text. pub(crate) fn push_default(&mut self, property: ResolvedProperty) { assert!(self.len != !0); - self.default_style.apply(property); + self.root_style.apply(property); } - /// Pushes a property that covers the specified range of text. + /// Override a property for the specified range of text. pub(crate) fn push(&mut self, property: ResolvedProperty, range: impl RangeBounds) { - let range = resolve_range(range, self.len); assert!(self.len != !0); + let range = resolve_range(range, self.len); self.properties.push(RangedProperty { property, range }); } @@ -53,11 +54,11 @@ impl RangedStyleBuilder { pub(crate) fn finish(&mut self, styles: &mut Vec>) { if self.len == !0 { self.properties.clear(); - self.default_style = ResolvedStyle::default(); + self.root_style = ResolvedStyle::default(); return; } styles.push(RangedStyle { - style: self.default_style.clone(), + style: self.root_style.clone(), range: 0..self.len, }); for prop in &self.properties { @@ -125,7 +126,7 @@ impl RangedStyleBuilder { styles.truncate(styles.len() - merged_count); self.properties.clear(); - self.default_style = ResolvedStyle::default(); + self.root_style = ResolvedStyle::default(); self.len = !0; } } diff --git a/parley/src/resolve/tree.rs b/parley/src/resolve/tree.rs index 39da3b95..f6ec5845 100644 --- a/parley/src/resolve/tree.rs +++ b/parley/src/resolve/tree.rs @@ -57,7 +57,9 @@ impl Default for TreeStyleBuilder { } impl TreeStyleBuilder { - /// Prepares the builder for accepting a style tree for text of the specified length. + /// Prepares the builder for accepting a tree of styles and text. + /// + /// The provided `root_style` is the default style applied to all text unless overridden. pub(crate) fn begin(&mut self, root_style: ResolvedStyle) { self.tree.clear(); self.flatted_styles.clear(); diff --git a/parley/src/tests/test_builders.rs b/parley/src/tests/test_builders.rs index 2fa8e363..28cf23e9 100644 --- a/parley/src/tests/test_builders.rs +++ b/parley/src/tests/test_builders.rs @@ -223,6 +223,36 @@ fn set_root_style(rb: &mut RangedBuilder<'_, ColorBrush>) { rb.push_default(StyleProperty::OverflowWrap(OverflowWrap::Anywhere)); } +/// Test that all the builders have the same default behavior. +#[test] +fn builders_default() { + let text = "Builders often wear hard hats for safety while working on construction sites."; + let scale = 2.; + let quantize = false; + let max_advance = Some(50.); + let root_style = TextStyle { + font_stack: FontStack::from(FONT_STACK), + ..TextStyle::default() + }; + + let with_ranged_builder = |rb: &mut RangedBuilder<'_, ColorBrush>| { + rb.push_default(FontStack::from(FONT_STACK)); + }; + let with_tree_builder = |tb: &mut TreeBuilder<'_, ColorBrush>| { + tb.push_text(text); + }; + + assert_builders_produce_same_result( + text, + scale, + quantize, + max_advance, + &root_style, + with_ranged_builder, + with_tree_builder, + ); +} + /// Test that all the builders behave the same when given the same root style. #[test] fn builders_root_only() {