Skip to content
Merged
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
6 changes: 2 additions & 4 deletions examples/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use std::time::Instant;
use parley::VerticalAlign;
use parley::fontique::Blob;
use parley::{
Alignment, AlignmentOptions, FontContext, FontFamily, FontWeight, GenericFamily, InlineBox,
InlineBoxKind, Layout, LayoutContext, LineHeight, StyleProperty,
FontContext, FontFamily, FontWeight, GenericFamily, InlineBox, InlineBoxKind, Layout,
LayoutContext, LineHeight, StyleProperty,
};
use peniko::Color;

Expand Down Expand Up @@ -156,7 +156,6 @@ pub fn build_simple_layout(

let mut layout = builder.build(&config.text);
layout.break_all_lines(config.max_advance);
layout.align(Alignment::Start, AlignmentOptions::default());

let width = layout.width().ceil() as u16;
let height = layout.height().ceil() as u16;
Expand Down Expand Up @@ -219,7 +218,6 @@ pub fn build_rich_layout(

let mut layout = builder.build(&config.text);
layout.break_all_lines(config.max_advance);
layout.align(Alignment::Start, AlignmentOptions::default());

let width = layout.width().ceil() as u16;
let height = layout.height().ceil() as u16;
Expand Down
5 changes: 2 additions & 3 deletions examples/swash_render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
use image::codecs::png::PngEncoder;
use image::{self, Pixel, Rgba, RgbaImage};
use parley::VerticalAlign;
use parley::layout::{Alignment, Glyph, GlyphRun, Layout, PositionedLayoutItem};
use parley::layout::{Glyph, GlyphRun, Layout, PositionedLayoutItem};
use parley::style::{FontFamily, FontWeight, StyleProperty, TextStyle};
use parley::{AlignmentOptions, FontContext, InlineBox, InlineBoxKind, LayoutContext, LineHeight};
use parley::{FontContext, InlineBox, InlineBoxKind, LayoutContext, LineHeight};
use std::fs::File;
use swash::FontRef;
use swash::scale::image::Content;
Expand Down Expand Up @@ -192,7 +192,6 @@ fn main() {

// Perform layout (including bidi resolution and shaping) with start alignment
layout.break_all_lines(max_advance);
layout.align(Alignment::Start, AlignmentOptions::default());

// Create image to render into
let width = layout.width().ceil() as u32 + (padding * 2);
Expand Down
5 changes: 2 additions & 3 deletions examples/tiny_skia_render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

use parley::VerticalAlign;
use parley::{
Alignment, AlignmentOptions, FontContext, FontWeight, GenericFamily, GlyphRun, InlineBox,
InlineBoxKind, Layout, LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty,
FontContext, FontWeight, GenericFamily, GlyphRun, InlineBox, InlineBoxKind, Layout,
LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty,
};
use skrifa::{
GlyphId, MetadataProvider, OutlineGlyph,
Expand Down Expand Up @@ -102,7 +102,6 @@ fn main() {

// Perform layout (including bidi resolution and shaping) with start alignment
layout.break_all_lines(max_advance);
layout.align(Alignment::Start, AlignmentOptions::default());
let width = layout.width().ceil() as u32;
let height = layout.height().ceil() as u32;
let padded_width = width + padding * 2;
Expand Down
3 changes: 1 addition & 2 deletions parley/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ See the [examples](https://github.com/linebender/parley/tree/main/examples) dire

```rust
use parley::{
Alignment, AlignmentOptions, FontContext, FontWeight, InlineBox, InlineBoxKind, Layout,
FontContext, FontWeight, InlineBox, InlineBoxKind, Layout,
LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty, VerticalAlign,
};

Expand Down Expand Up @@ -91,7 +91,6 @@ let mut layout: Layout<()> = builder.build(&TEXT);
// Run line-breaking and alignment on the Layout
const MAX_WIDTH : Option<f32> = Some(100.0);
layout.break_all_lines(MAX_WIDTH);
layout.align(Alignment::Start, AlignmentOptions::default());

// Inspect computed layout (see examples for more details)
let width = layout.width();
Expand Down
9 changes: 4 additions & 5 deletions parley/src/editing/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,9 @@ where
// Not all operations on `PlainEditor` need to operate on a
// clean layout, and not all operations trigger a layout.
layout_dirty: bool,
// TODO: We could avoid redoing the full text layout if only
// linebreaking or alignment were changed.
// TODO: We could avoid redoing the full text analysis if only
// dimensions or alignment were changed.
// linebreak_dirty: bool,
// alignment_dirty: bool,
alignment: Alignment,
base_direction: BaseDirection,
generation: Generation,
Expand Down Expand Up @@ -1207,9 +1206,9 @@ where
builder.push(StyleProperty::Underline(true), preedit_range.clone());
}
builder.build_into(&mut self.layout, &self.buffer);
self.layout.break_all_lines(self.width);
self.layout
.align(self.alignment, AlignmentOptions::default());
.set_alignment(self.alignment, AlignmentOptions::default());
self.layout.break_all_lines(self.width);
self.selection = self.selection.refresh(&self.layout);
self.layout_dirty = false;
self.generation.nudge();
Expand Down
21 changes: 11 additions & 10 deletions parley/src/layout/alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub enum Alignment {
}

/// Additional options to fine tune alignment
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AlignmentOptions {
/// If set to `true`, "end" and "center" alignment will apply even if the line contents are
/// wider than the alignment width. If it is set to `false`, all overflowing lines will be
Expand All @@ -44,11 +44,11 @@ pub struct AlignmentOptions {
/// line that ends in an explicit line break. This corresponds to the CSS `text-align-last`
/// property.
///
/// If set to `None`, those lines use the alignment passed to [`Layout::align`], except that
/// [`Alignment::Justify`] falls back to [`Alignment::Start`]. This is the behavior of
/// If set to `None`, those lines use the alignment passed to [`Layout::set_alignment`], except that
/// [`Alignment::Justify`] falls back to [`Alignment::Start`]. This is the behavior of
/// `text-align-last: auto`.
///
/// [`Layout::align`]: crate::Layout::align
/// [`Layout::set_alignment`]: crate::Layout::set_alignment
pub last_line_alignment: Option<Alignment>,
}

Expand All @@ -65,12 +65,13 @@ impl Default for AlignmentOptions {
}
}

/// Align the layout.
pub(crate) fn align<B: Brush>(
layout: &mut LayoutData<B>,
alignment: Alignment,
options: AlignmentOptions,
) {
/// Align the layout. This applies to the full layout at a time, because the alignment implicitly
/// uses the widest width in the layout if no max advance was provided.
///
/// TODO: Evaluate whether aligning a line at a time might be faster (better cache locality?).
pub(crate) fn align<B: Brush>(layout: &mut LayoutData<B>) {
let alignment = layout.alignment_setting;
let options = layout.alignment_options;
layout.alignment = Some(alignment);

let is_rtl = layout.base_level.is_rtl();
Expand Down
6 changes: 3 additions & 3 deletions parley/src/layout/cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,21 +548,21 @@ mod tests {

type Brush = ();

fn create_unaligned_layout() -> Layout<Brush> {
fn create_layout(alignment: Alignment) -> Layout<Brush> {
let mut layout_ctx = LayoutContext::new();
// TODO: Use a test font
let mut font_ctx = FontContext::new();
let text = "Parley exists";
let mut builder = layout_ctx.ranged_builder(&mut font_ctx, text, 1.0, true);
builder.push_default(StyleProperty::FontSize(10.));
let mut layout = builder.build(text);
layout.set_alignment(alignment, AlignmentOptions::default());
layout.break_all_lines(None);
layout
}

fn cluster_from_position_with_alignment(alignment: Alignment) {
let mut layout = create_unaligned_layout();
layout.align(alignment, AlignmentOptions::default());
let layout = create_layout(alignment);
assert_eq!(
layout.len(),
1,
Expand Down
18 changes: 13 additions & 5 deletions parley/src/layout/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ pub(crate) struct LayoutData<B: Brush> {
pub(crate) runs: Vec<RunData>,
pub(crate) items: Vec<LayoutItem>,

// Settings for line breaking and alignment
pub(crate) alignment_setting: super::Alignment,
pub(crate) alignment_options: super::AlignmentOptions,
/// The text-indent amount in layout units.
pub(crate) indent_amount: f32,
/// Options controlling text-indent behavior.
pub(crate) indent_options: IndentOptions,

// Output of line breaking
/// The lines in the
pub(crate) lines: Vec<LineData>,
Expand All @@ -228,12 +236,8 @@ pub(crate) struct LayoutData<B: Brush> {
pub(crate) height: f32,

// Output of alignment
/// The alignment that was applied to the layout, if any.
/// The alignment that was applied when the layout was line broken, if any.
pub(crate) alignment: Option<super::Alignment>,
/// The text-indent amount in layout units.
pub(crate) indent_amount: f32,
/// Options controlling text-indent behavior (each-line, hanging).
pub(crate) indent_options: IndentOptions,
}

impl<B: Brush> Default for LayoutData<B> {
Expand All @@ -255,6 +259,8 @@ impl<B: Brush> Default for LayoutData<B> {
lines: Vec::new(),
line_items: Vec::new(),
aligned_subtree_offsets: Vec::new(),
alignment_setting: super::Alignment::default(),
alignment_options: super::AlignmentOptions::default(),
alignment: None,
layout_max_advance: 0.0,
indent_amount: 0.0,
Expand Down Expand Up @@ -284,6 +290,8 @@ impl<B: Brush> LayoutData<B> {
self.lines.clear();
self.line_items.clear();
self.aligned_subtree_offsets.clear();
self.alignment_setting = super::Alignment::default();
self.alignment_options = super::AlignmentOptions::default();
self.alignment = None;
}

Expand Down
44 changes: 24 additions & 20 deletions parley/src/layout/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

use crate::IndentOptions;
use crate::InlineBox;
use crate::layout::alignment::align;
use crate::layout::data::LayoutData;
use crate::layout::style_metrics::StyleMetrics;
use crate::layout::{
Expand Down Expand Up @@ -88,9 +87,10 @@ impl<B: Brush> Layout<B> {
self.data.text_len
}

/// Returns the alignment that was applied to the layout by [`Layout::align`].
/// Returns the alignment that was active when lines were most recently broken.
///
/// Returns `None` if the layout has not been aligned since it was last built.
/// This returns `None` if [`Layout::break_all_lines`] or [`Layout::break_lines`] have
/// not been called since the layout was last built or [cleared](Self::clear).
pub fn alignment(&self) -> Option<Alignment> {
self.data.alignment
}
Expand Down Expand Up @@ -267,14 +267,33 @@ impl<B: Brush> Layout<B> {
/// available width for line breaking and offsetting content during alignment. Negative
/// values cause the line to protrude beyond the start edge.
///
/// This must be called before [`Layout::break_all_lines`] or [`Layout::break_lines`],
/// and before [`Layout::align`].
/// This must be called before [`Layout::break_all_lines`] or [`Layout::break_lines`].
/// The text indentation is reset to zero when the layout is [cleared](Self::clear) or built into.
pub fn set_text_indent(&mut self, amount: f32, options: IndentOptions) {
self.data.indent_amount = amount;
self.data.indent_options = options;
}

/// Set the alignment for the layout.
///
/// This only takes effect the next time [`Layout::break_all_lines`] or [`Layout::break_lines`] is called.
/// The currently active value can be read as [`Self::alignment`].
///
/// If a finite `max_advance` is supplied to `Layout::break_all_lines` then alignment will be applied
/// relative to that width. Otherwise alignment will be applied relative to the width of the
/// longest line as computed by line breaking.
///
/// If line-specific `offset` and `max_advance` are set using the advanced methods on the `BreakLines`
/// struct then each line will be aligned individually within its line box.
///
/// The alignment to be used is reset to [`Alignment::Start`] when the layout is [cleared](Self::clear) or built into.
pub fn set_alignment(&mut self, alignment: Alignment, options: AlignmentOptions) {
self.data.alignment_setting = alignment;
self.data.alignment_options = options;
}

/// Returns line breaker to compute lines for the layout.
// TODO: You must call [`BreakLines::finish`]?
pub fn break_lines(&mut self) -> BreakLines<'_, B> {
BreakLines::new(self)
}
Expand All @@ -285,21 +304,6 @@ impl<B: Brush> Layout<B> {
.break_remaining(max_advance.unwrap_or(f32::MAX));
}

/// Apply alignment to the layout.
///
/// You must perform line breaking prior to aligning, through [`Layout::break_lines`] or
/// [`Layout::break_all_lines`].
///
/// If a finite `max_advance` is supplied to `Layout::break_all_lines` then that width will be applied
/// relative to that width. Otherwise alignment will be applied relative to the width of the
/// longest line as computed by line breaking.
///
/// If line-specific `offset` and `max_advance` are set using the advanced methods on the `BreakLines`
/// struct then each line will be aligned individually within its line box.
pub fn align(&mut self, alignment: Alignment, options: AlignmentOptions) {
align(&mut self.data, alignment, options);
}

/// Returns the index and `Line` object for the line containing the
/// given byte `index` in the source text.
pub(crate) fn line_for_byte_index(&self, index: usize) -> Option<(usize, Line<'_, B>)> {
Expand Down
4 changes: 4 additions & 0 deletions parley/src/layout/line_break.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,8 @@ impl<'a, B: Brush> BreakLines<'a, B> {

impl<B: Brush> Drop for BreakLines<'_, B> {
fn drop(&mut self) {
// TODO: Maybe move all of this into `finish`?

// Compute the overall width and height of the entire layout
// The "width" excludes hanging whitespace. The "full_width" includes it.
let mut layout_width = 0_f32;
Expand Down Expand Up @@ -1683,6 +1685,8 @@ impl<B: Brush> Drop for BreakLines<'_, B> {

// Save the computed lines to the layout
self.lines.swap(&mut self.layout.data);

crate::layout::alignment::align(&mut self.layout.data);
}
}

Expand Down
2 changes: 1 addition & 1 deletion parley/src/layout/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl<'a, B: Brush> Run<'a, B> {
/// Returns the advance for the run.
///
/// This includes the additional advances inserted for word spacing, letter spacing, and, if the
/// layout has been [aligned](Layout::align) with [`Justify`](crate::Alignment::Justify), the
/// layout has been [aligned](Layout::set_alignment) with [`Justify`](crate::Alignment::Justify), the
/// justification.
pub fn advance(&self) -> f32 {
let spacing = self.line_spacing();
Expand Down
3 changes: 1 addition & 2 deletions parley/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
//!
//! ```rust
//! use parley::{
//! Alignment, AlignmentOptions, FontContext, FontWeight, InlineBox, InlineBoxKind, Layout,
//! FontContext, FontWeight, InlineBox, InlineBoxKind, Layout,
//! LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty, VerticalAlign,
//! };
//!
Expand Down Expand Up @@ -60,7 +60,6 @@
//! // Run line-breaking and alignment on the Layout
//! const MAX_WIDTH : Option<f32> = Some(100.0);
//! layout.break_all_lines(MAX_WIDTH);
//! layout.align(Alignment::Start, AlignmentOptions::default());
//!
//! // Inspect computed layout (see examples for more details)
//! let width = layout.width();
Expand Down
2 changes: 1 addition & 1 deletion parley/src/tests/test_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ fn clear_resets_to_new() {
builder.push_default(FontFamily::from(FONT_FAMILY_LIST));
let mut layout = builder.build(TEXT);
layout.set_text_indent(10., IndentOptions::default());
layout.set_alignment(Alignment::Center, AlignmentOptions::default());
layout.break_all_lines(Some(50.));
layout.align(Alignment::Center, AlignmentOptions::default());
assert!(layout.lines().len() > 1);
assert!(layout.width() > 0.);
assert!(layout.height() > 0.);
Expand Down
4 changes: 1 addition & 3 deletions parley_bench/benches/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
use tango_bench::tango_benchmarks;

use parley_bench::benches::{
content_widths, defaults, iterate_glyph_runs, line_breaking, long_line, page,
repeated_justification, spacing, styled,
content_widths, defaults, iterate_glyph_runs, line_breaking, long_line, page, spacing, styled,
};
use parley_bench::fontique_benches::system_fonts_init;
use parley_bench::query_benches::cursor;
Expand All @@ -18,7 +17,6 @@ tango_benchmarks!(
iterate_glyph_runs(),
content_widths(),
spacing(),
repeated_justification(),
line_breaking(),
long_line(),
page(),
Expand Down
Loading
Loading