Repository navigation
| Name | Crates.io | Docs |
|---|---|---|
parley |
Crates.io | Docs |
parley_data |
Crates.io | Docs |
parley_emoji |
Crates.io | Docs |
parley_engine |
Crates.io | Docs |
fontique |
Crates.io | Docs |
This release has an MSRV of 1.88.
Highlights
Parley Engine
This release introduces parley_engine, a lower-level crate for applications that need more control over text layout than Parley's web-style model allows, such as typesetters implementing their own line-breaking algorithms. Parley itself is now built on top of it.
Parley Engine analyzes paragraphs of text, resolving details like line break opportunities, grapheme boundaries, bidirectional text embedding levels, and emoji presentation, and shapes them with caller-provided font selection. Layout decisions, such as where to break lines and how to align or stack them, are left to the caller. Work is underway to support reshaping of lines, e.g., when a break falls within a ligature or splits a word in a cursive script.
Whitespace handling
Parley now implements whitespace hanging rules following CSS Text 4, and parley::TreeBuilder can now collapse whitespace according to CSS's white-space-collapse property; see style::WhiteSpaceCollapse.
Vertical alignment
Lines in a layout are now sized more closely to the CSS line box model. Inline boxes and spans of text can be vertically aligned following the keywords and lengths of CSS 2.2's vertical-align; see style::VerticalAlign.
Grapheme clusters
parley::layout::Cluster now spans whole extended grapheme clusters, instead of single characters. Carets and selections no longer land inside graphemes (such as between a letter and its combining accent); within a ligature, carets land between its graphemes at evenly spaced positions.
Added
Parley
- Breaking change: The baselines of inline boxes can now be specified. (#639 by @nicoburns)
- Breaking change: The
VerticalAlignstyle, allowing vertical alignment of inline spans to be specified. (#766 by @nicoburns)
Layout::{inline_boxes, inline_boxes_mut}now returnimpl ExactSizeIteratorinstead of slices. - Breaking change:
AlignmentOptions::last_line_alignment, which allows the alignment of the last line to be configured. (#872 by @nicoburns)
This is especially useful in combination with justification. - Breaking change: Added the
WhiteSpaceCollapse::{PreserveBreaks, BreakSpaces}variants. (#812, #833 by @nicoburns) - Breaking change: Support for the CSS
line-breakstyle. This controls line-breaking behaviour of CJK text. (#843 by @nicoburns) - Breaking change: Added
LineMetrics::content_block_{min, max}_coord, which are the typographic content bounds of a line independent of line height. (#697 by @tomcur) - Breaking change: Added
LineMetrics::indent, which is the text indent applied to the line. (#893 by @tomcur) Layout::text_lenandLayout::alignment,Cursor::upstream_clusterandCursor::downstream_cluster,PlainEditor::is_cursor_visible, andPlainEditorDriver::set_selection. (#716 by @DataTriny and @nicoburns)
ClusterPath::newand theStyle::localefield are now public as well.
Together these make it possible to build an accessibility integration outside of Parley.Layout::root_span_metrics, to help with placing directly drawn bullet points. (#867 by @DJMcNab)Cluster::style_indexandGlyphRun::style_index. (#661 by @tomcur)- The base direction of paragraphs can now be set using
{RangedBuilder, StyleRunBuilder, TreeBuilder, PlainEditor}::set_base_direction. (#708 by @waywardmonkeys, #858 by @nicoburns) Layout::clearto clear the contents of a layout. This can be used to clean up font resources. (#804 by @taj-p)ClusterandRunare nowCopyandClonefor any brush. (#715 by @tomcur)TreeBuilder::text()andTreeBuilder::has_pending_whitespace(), which allow the current state of theTreeBuilder's processed text to be inspected. (#856 by @nicoburns)
Parley Engine
- Initial release. See the highlights above. (@tomcur, with contributions from @DJMcNab, @fundon, @GoCoder7, @nicoburns, @Soundcreates, @taj-p and @waywardmonkeys)
Fontique
Changed
Parley
- Breaking change:
Clusternow spans a full grapheme cluster instead of a single character. (#715 by @tomcur)
Shaped clusters that cross grapheme boundaries are represented using the existingCluster::is_ligature_startandCluster::is_ligature_continuation; note these methods previously encoded graphemes as well.
Shaped clusters' advances are split evenly over the grapheme clusters they overlap.
Run::cluster_rangenow returns grapheme cluster indices relative to the run's shaped run. - Breaking change: lines with mixed inline content, like different fonts or sizes, or inline boxes, are now sized more closely to the CSS line-box model. (#697 by @tomcur)
TheLineMetrics::{ascent,descent,leading}fields were removed, andLineMetrics::block_{min,max}_coordnow describe the block-axis layout bounds of each line box.
Glyphs may overflow these layout bounds, especially when a small line height is used.
LineMetrics::content_block_{min,max}_coordprovide the typographic content bounds, covering typographic ascent and descent as well as inline boxes, ignoring the specified line height.
Note glyphs overflow these content bounds as well, for example when many combining marks are stacked.
The union of the line-box and content bounds is close to the oldLineMetrics::block_{min,max}_coordfields. - Breaking change:
layout::Cluster::first_stylewas renamed tolayout::Cluster::style. (#660 by @tomcur) - Breaking change:
WhiteSpaceCollapseis now a style, andTreeBuilder::set_white_space_modewas removed. (#814 by @nicoburns) - Breaking change:
LineMetrics::trailing_whitespacewas renamed toLineMetrics::hanging_advance. Following CSS Text 4 § 4.3.2, non-breaking spaces no longer hang past line ends. (#762 by @tomcur) - Breaking change:
LineBreakData::{advance, line_height}were replaced byLineBreakData::metrics, which holds the line's fullLineMetrics. (#892 by @nicoburns, #893 by @tomcur) - Breaking change:
Run::normalized_coordsnow returns&[NormalizedCoord]instead of&[i16]. (#679 by @tomcur)
UseNormalizedCoord::to_bits, or cast the slice using the newbytemuckfeature. - Ideographic spaces can now hang past line ends. (#784 by @tomcur)
- Following CSS Text 4 § 4.3.2, trailing
WhiteSpaceCollapse::Preservewhitespace before a forced line break or at the end of the text now hangs only as far as it overflows the line. (#790 by @tomcur) - Applying letter spacing now stops optional ligatures from forming. (#731 by @tomcur)
- OutOfFlow inline boxes no longer produce line-break opportunities (#797 by @nicoburns)
- When no fonts are returned by the font query, Parley now falls back to selecting any font from the collection. (#722 by @tomcur)
Fontique
- Synthetic font emboldening is now only requested if the weight difference is greater than 200. (#724 by @taj-p)
- The
&QueryFontpassed byQuery::matches_withnow lives as long as the query borrow itself. (#841 by @tomcur)
Removed
Parley
- Breaking change: the
accesskitfeature, and the AccessKit integration it enabled, were removed. (#716 by @DataTriny and @nicoburns)
The integration now lives in theeditorexample, where it is easier to evolve and can be copied and adapted by consumers.
This removedLayoutAccessibility,PlainEditor::try_accessibility,PlainEditorDriver::accessibility,PlainEditorDriver::select_from_accesskit,Cursor::from_access_position,Cursor::to_access_position,Selection::from_access_selection, andSelection::to_access_selection. - Breaking change:
ClusterPath::logical_indexwas removed. You can resolve the path to aClusterusingClusterPath::cluster.ClusterPathstill provides the line and run indices, but should otherwise be treated as an opaque handle. (#810 by @tomcur) - Breaking change:
layout::Run::{logical_to_visual, visual_to_logical}were removed. Uselayout::Run::visual_clustersorlayout::Cluster::{next, previous}_visualinstead. (#810 by @tomcur) - Breaking change: the
Glyph::style_indexfield was removed. UseCluster::{style, style_index}orGlyphRun::{style, style_index}instead. (#661 by @tomcur) - Breaking change:
layout::Run::metrics()was removed, uselayout::Run::font_metrics()instead. (#679 by @tomcur)
Fixed
Parley
- Shaping across style boundaries now uses the surrounding context to select the correct glyphs. (#740 by @tomcur)
- Cursor movement and hit-testing no longer place the caret inside grapheme clusters. (#715 by @tomcur)
editing::Cursor::{previous,next}_logical_wordnow land at the previous/next logical start of a word and skip over whitespace. (#215 by @tomcur)- Letter and word spacing is now applied once per grapheme. Previously, spacing was mistakenly counted for each character in the grapheme. (#738 by @tomcur)
Layout::widthno longer under-reports widths when there are explicit newlines present and the style has non-zero letter spacing. Previously, an explicit newline would erroneously subtract the configured letter spacing from its line. (#738 by @tomcur)- Shaping now honours script and region subtags for correct handling of, for example, zh-Hans and zh-Hant. (#756 by @taj-p @DJMcNab)
- All line height changes within a run now contribute to the line box. (#863, #864 by @tomcur)
- Fix
calculate_content_widthswhen an inline box immediately follows a hard/explicit newline. It was previously incorrectly counted as being before the newline. (#746 by @nicoburns, #772 by @tomcur) - In
calculate_content_widths, the max-content width is now floored by the min-content width. (#834 by @nicoburns)
This follows CSS in guarding against cases where the max-content width could be smaller than the min-content width, e.g., in the presence of inline boxes with negative margins. Layout::calculate_content_widthsnow correctly handles hanging of consecutive trailing white space and trailing white space consisting of separate runs (e.g., due to font size changes). (#785 by @tomcur)Layout::calculate_content_widthsnow accounts for text indent. (#866 by @nicoburns, #889 by @tomcur)- Justification of lines with overflowing trailing spaces now correctly distributes free space over all interior spaces. (#738 by @tomcur)
- Lines aligned with justification now correctly handle runs of consecutive trailing spaces. (#760 by @tomcur)
- Trailing white space consisting of separate runs (e.g., due to font size changes) now hangs past line ends. (#762 by @tomcur)
- Collapsible white space is now collapsed across style span and inline box boundaries instead of being trimmed at each span boundary, and is removed around hard line breaks. (#786 by @nicoburns and @tomcur)
- Non-breaking spaces are now preserved when collapsing whitespace. (#734 by @subotac)
- Mandatory line breaks (
\n,\r\n, U+2028, U+2029) directly following Thai, Khmer or Lao text are no longer dropped. (#781 by @nicoburns) - Text that shapes into zero glyphs is no longer silently dropped. (#805 by @tomcur)
This fixes some esoteric interactions, such as the string\r\u{00AD}\nlosing the mandatory newline if the\u{00AD}soft-hyphen was shaped with a font missing a space glyph. - When using the
TreeBuilder, out-of-flow boxes are now correctly positioned within the text. (#815 by @tomcur) - Parley's detection of Emoji is now more robust. (#811 by @fundon and @DJMcNab)
- Fixed CJK and Korean word boundary navigation in
Cluster::is_word_boundary(), properly distinguishing UAX #29 word boundaries from UAX #14 line break opportunities. (#819 by @GoCoder7, #829 by @tomcur)
Word boundaries of complex scripts, in the absence of dictionary data, now follow Unicode rules. - Apply
TextWrapMode::NoWrapto line-breaking opportunities following inline boxes (#844 by @nicoburns) PlainEditor::set_textno longer crashes on the next edit when the old cursor is outside the new text; the cursor is clamped to the new text. (#850 by @teolines)- In case a font does not carry decoration metrics like underline size, the fallbacks now scale with the font size instead of staying in font units, and the fallback underline is now placed below the baseline instead of above. (#878 by @tomcur)
- Fix reporting of soft wrap opportunities around forced breaks. (#676 by @DJMcNab, #838 by @tomcur)
\r\nnow gives a single forced break instead of two. (#667 by @mvanhorn, #824 by @tomcur)- The root style is now consistently passed through when the text is empty. (#721 by @tomcur)
- State tracking of
YieldData::MaxHeightExceededhas been corrected. (#853 by @nicoburns) - Fix infinite loop in
break_remainingwithCustomOutOfFlowinline boxes. (#753 by @nicoburns)
Fontique
- Fix compilation on 32-bit platforms without 64-bit atomics (e.g.
mipsel-unknown-linux-gnu). (#672 by @nicoburns) - Don't panic when fontconfig exposes no fonts. (#717 by @ogoffart)
Collection::load_fonts_from_pathsno longer registers duplicate faces. (#754 by @ChrisJr404)- All coverage variants for a family are now included in the query. (#663 by @kane50613)
- Select the correct variable font weight in synthesis when the default and declared weights conflict. (#723 by @taj-p)
New Contributors
- @mvanhorn made their first contribution in #654
- @subotac made their first contribution in #734
- @GoCoder7 made their first contribution in #819
- @DataTriny made their first contribution in #716
- @teolines made their first contribution in #850
- @ChrisJr404 made their first contribution in #754
Full Changelog: v0.11.1...v0.12.0