Conversation
8715454 to
d5acb19
Compare
d5acb19 to
d84175b
Compare
nicoburns
left a comment
There was a problem hiding this comment.
This mostly looks good to me. But we also need to make sure the RTL case is working correctly. Can we get tests for RTL case? And I think the fix I have suggested for the offset may be required.
We should also check that hit testing / cursor placement / selection works correctly with indented text (including text that overflows the bounds of it's box due to negative text indent).
2b5a290 to
c318240
Compare
- Simplify hanging indent logic using XOR (is_scope_line ^ hanging) - Add RTL text indent tests (basic, hanging, each_line, negative, center, justify) - Add hit testing, cursor placement, and selection geometry tests for indented text - Add negative indent overflow hit testing test
c318240 to
ea76822
Compare
|
Addressed review feedback:
|
nicoburns
left a comment
There was a problem hiding this comment.
I have one suggestion around method naming. Otherwise this LGTM now. But I'll give other maintainers a chance to review before merging.
I've tested that hit testing / mouse selection logic works correctly in Blitz.
| /// | ||
| /// This must be called before [`Layout::break_all_lines`] or [`Layout::break_lines`], | ||
| /// and before [`Layout::align`]. | ||
| pub fn indent(&mut self, amount: f32, options: IndentOptions) { |
There was a problem hiding this comment.
Could we name this set_text_indent. Because unlike the align method it doesn't actually apply the indent to the text (it just sets the style).
Closes #545
Summary
Adds CSS
text-indentsupport to parley. The indent is treated as a margin on the start edge of the line box (per CSS spec), reducing available width during line breaking and offsetting content during alignment.Design decisions
StyleProperty—text-indentis a block-level CSS property, so it follows the same pattern asAlignment: stored inLayoutData, configured via a method onLayout.Layout::align()—Layout::indent(amount, options)separates the core value from behavioral options.LineData— computed once during line breaking, reused during alignment without recalculation.IndentOptionsinlayoutmodule — since text-indent is a layout-level property (not a per-span style),IndentOptionslives inlayout/mod.rsalongsideAlignment,AlignmentOptions, andContentWidths.Features
each-linekeyword — indent applies after every hard line break (BreakReason::Explicit), not just the first line.hangingkeyword — inverts which lines are indented: continuation lines instead of first line(s).Start,Center,Right, andJustifyalignments. Indent acts as a start-edge margin, and alignment operates within the remaining space.API
How it works
Line breaking (
line_break.rs):each_lineandhangingoptions.max_advanceto reduce available width for the indented line.LineData::indent.Dropadds positive indent to line advance (negative indent causes overflow, not box growth).Alignment (
alignment.rs):offset = indent(previously always0).free_spaceso alignment algorithms (center, end, justify) operate within the reduced space.Changes
parley/src/layout/mod.rsIndentOptionsstructparley/src/layout/data.rsindent_amount/indent_optionstoLayoutData,indenttoLineDataparley/src/layout/layout.rsLayout::indent()public APIparley/src/layout/line_break.rsbreak_next, propagation throughtry_commit_line, width accounting inDropparley/src/layout/alignment.rsparley_tests/tests/text_indent.rsTest plan
cargo check -p parley— compilescargo test -p parley— 49 passed (existing unit tests unaffected)cargo clippy -p parley -p parley_tests— no warningscargo test -p parley_tests— 125 passed (103 existing + 22 new)New test cases
text_indent_basictext_indent_no_wraptext_indent_each_line\n)text_indent_hangingtext_indent_hanging_each_linetext_indent_negativetext_indent_negative_hangingtext_indent_center_alignmenttext_indent_right_alignmenttext_indent_justifytext_indent_zerotext_indent_line_breakingtext_indent_rtl_basictext_indent_rtl_hangingtext_indent_rtl_each_linetext_indent_rtl_negativetext_indent_rtl_center_alignmenttext_indent_rtl_justifytext_indent_cursor_geometrytext_indent_hit_testingtext_indent_negative_hit_testingtext_indent_selection_geometry