mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-02 06:36:51 -06:00
Drop caps: tabs in right-to-left drop caps advance to the tab stops
Measured from the column's right edge, past the right indent.
This commit is contained in:
+19
-17
@@ -695,7 +695,8 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C
|
||||
let drop_grid = cur_frame.and_then(|f| f.grid).filter(|_| pp.grid_align == GridAlign::AllLines).map(|g| g.1);
|
||||
// Align Left Edge (left-to-right paragraphs).
|
||||
let drop_align = pp.drop_cap_align_left && pp.direction == designcraft_doc::TextDirection::LeftToRight;
|
||||
let drop_tabs = (pp.direction == designcraft_doc::TextDirection::LeftToRight).then_some((&pp.tabs[..], pp.left_indent));
|
||||
// Tab stops for the drop cap, with the start-side indent (the right one, right to left).
|
||||
let drop_tabs = (&pp.tabs[..], if pp.direction == designcraft_doc::TextDirection::RightToLeft { pp.right_indent } else { pp.left_indent });
|
||||
if !pp.nested_line_styles.is_empty() && cur.fi < frames.len() {
|
||||
// Nested line styles: find where the first lines end in this column, restyle them, and
|
||||
// look again (the style changes the widths) until the lines settle.
|
||||
@@ -2869,9 +2870,10 @@ struct DropCap {
|
||||
/// it so its cap height reaches from the first line's cap height down to line `lines`' baseline,
|
||||
/// measured in the leading and cap height of the text after it. A one-line drop cap keeps its own
|
||||
/// size when that is smaller. On a baseline grid of increment `grid`, lines are that many grid
|
||||
/// steps apart. With `align_left` its ink starts at the indent (see [`DropCap::lsb`]). `tabs`
|
||||
/// (stops and left indent, left-to-right paragraphs) sets the tabs inside it. Spaces right after
|
||||
/// it join it at its size without widening it.
|
||||
/// steps apart. With `align_left` its ink starts at the indent (see [`DropCap::lsb`]). Tabs inside
|
||||
/// it advance to the stops of `tabs` (stops and the start-side indent; in right-to-left paragraphs
|
||||
/// both measured from the column's right edge). Spaces right after it join it at its size without
|
||||
/// widening it.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn split_drop_cap(
|
||||
db: &ScopedFonts<'_>,
|
||||
@@ -2882,7 +2884,7 @@ fn split_drop_cap(
|
||||
base_cap: f64,
|
||||
grid: Option<f64>,
|
||||
align_left: bool,
|
||||
tabs: Option<(&[designcraft_doc::TabStop], f64)>,
|
||||
tabs: (&[designcraft_doc::TabStop], f64),
|
||||
) -> Option<DropCap> {
|
||||
let n = glyphs.iter().take_while(|g| g.byte < end).count();
|
||||
if n == 0 {
|
||||
@@ -2926,19 +2928,19 @@ fn split_drop_cap(
|
||||
}
|
||||
_ => 0.0,
|
||||
};
|
||||
// Tabs advance to the paragraph's stops, measured from the column edge as in its lines.
|
||||
if let Some((stops, left_indent)) = tabs {
|
||||
let mut x = left_indent - lsb;
|
||||
for i in 0..dc.len() {
|
||||
let tab = match dc.get(i) {
|
||||
Some(g) if g.ch == '\t' => Some(tab_advance(stops, left_indent, x, dc.get(i + 1..).unwrap_or_default()).0),
|
||||
_ => None,
|
||||
};
|
||||
if let (Some(w), Some(g)) = (tab, dc.get_mut(i)) {
|
||||
g.adv = w;
|
||||
}
|
||||
x += dc.get(i).map_or(0.0, |g| g.adv);
|
||||
// Tabs advance to the paragraph's stops, measured from the column's start edge. Right to left,
|
||||
// its glyphs run from that (right) edge in this order (see `place_drop_cap`).
|
||||
let (stops, indent) = tabs;
|
||||
let mut x = indent - lsb;
|
||||
for i in 0..dc.len() {
|
||||
let tab = match dc.get(i) {
|
||||
Some(g) if g.ch == '\t' => Some(tab_advance(stops, indent, x, dc.get(i + 1..).unwrap_or_default()).0),
|
||||
_ => None,
|
||||
};
|
||||
if let (Some(w), Some(g)) = (tab, dc.get_mut(i)) {
|
||||
g.adv = w;
|
||||
}
|
||||
x += dc.get(i).map_or(0.0, |g| g.adv);
|
||||
}
|
||||
let width = dc.iter().map(|g| g.adv).sum();
|
||||
dc.append(&mut after);
|
||||
|
||||
@@ -2209,6 +2209,28 @@ fn one_line_drop_cap_keeps_its_size_and_sets_its_tabs() {
|
||||
assert!((text_x(l, 3) - 40.0).abs() < 1e-6, "the text starts at the left tab: {}", text_x(l, 3));
|
||||
}
|
||||
|
||||
/// Right to left, the tabs in a drop cap advance to tab stops measured from the column's right
|
||||
/// edge.
|
||||
#[test]
|
||||
fn right_to_left_drop_cap_sets_its_tabs_from_the_right_edge() {
|
||||
let stop = |position, align| designcraft_doc::TabStop { position, align, leader: String::new(), align_on: String::new() };
|
||||
let para = ParaAttrs {
|
||||
direction: Some(designcraft_doc::TextDirection::RightToLeft),
|
||||
align: Some(Align::Right),
|
||||
tabs: Some(vec![stop(30.0, TabAlign::Right), stop(40.0, TabAlign::Left)]),
|
||||
..drop_cap(1, 3)
|
||||
};
|
||||
let (d, sid, _) = drop_doc(&format!("\t7\t{LOREM}"), para);
|
||||
let cs = compose_story(&d, sid, &ComposeOptions::default());
|
||||
let l = &cs.frames[0].lines[0];
|
||||
let seven = l.glyphs.iter().find(|g| g.byte == 1).unwrap();
|
||||
// The 300 pt column's right edge is at 300: the number's far (left) end is 30 pt from it.
|
||||
assert!((seven.x - 270.0).abs() < 1e-6, "the number ends at the right tab: {}", seven.x);
|
||||
// The text beside it starts at the left tab, 40 pt from the edge.
|
||||
let right = l.glyphs.iter().filter(|g| g.byte >= 3 && g.visible).map(|g| g.x + g.adv).fold(f64::NEG_INFINITY, f64::max);
|
||||
assert!(right <= 260.0 + 1e-6 && right > 255.0, "text ends at {right}");
|
||||
}
|
||||
|
||||
/// A rule in Text Color takes the colour of the paragraph's text: the first character's for the
|
||||
/// rule above, the last character's for the rule below. A swatch colour is used as is.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user