diff --git a/crates/core/src/document/html/engine.rs b/crates/core/src/document/html/engine.rs
index a7afabe..6f76a1e 100644
--- a/crates/core/src/document/html/engine.rs
+++ b/crates/core/src/document/html/engine.rs
@@ -943,7 +943,15 @@ impl Engine {
} else if end_index < text.len() {
let penalty = if c == '-' { self.hyphen_penalty } else { 0 };
let flagged = penalty > 0;
- items.push(ParagraphItem::Penalty { width: 0, penalty, flagged });
+ if matches!(parent_style.text_align, TextAlign::Justify | TextAlign::Center) {
+ items.push(ParagraphItem::Penalty { width: 0, penalty, flagged });
+ } else {
+ let stretch = 3 * space_plan.glyph_advance(0);
+ items.push(ParagraphItem::Penalty { width: 0, penalty: INFINITE_PENALTY, flagged: false });
+ items.push(ParagraphItem::Glue { width: 0, stretch, shrink: 0 });
+ items.push(ParagraphItem::Penalty { width: 0, penalty: 10*penalty, flagged: true });
+ items.push(ParagraphItem::Glue { width: 0, stretch: -stretch, shrink: 0 });
+ }
}
}
start_index += chunk.len();
@@ -1004,11 +1012,6 @@ impl Engine {
style.text_indent
};
- let stretch_tolerance = if style.text_align == TextAlign::Justify {
- self.stretch_tolerance
- } else {
- 10.0
- };
let (ascender, descender) = {
let fonts = self.fonts.as_mut().unwrap();
let font = fonts.get_mut(style.font_kind, style.font_style, style.font_weight);
@@ -1118,25 +1121,21 @@ impl Engine {
let mut line_lengths: Vec = para_shape.iter().map(|(a, b)| b - a).collect();
line_lengths[0] -= text_indent;
- let mut bps = total_fit(&items, &line_lengths, stretch_tolerance, 0);
+ let mut bps = total_fit(&items, &line_lengths, self.stretch_tolerance, 0);
let mut hyph_indices = Vec::new();
let mut glue_drifts = Vec::new();
- if bps.is_empty() {
- let dictionary = if style.text_align == TextAlign::Justify {
- hyph_lang(style.language.as_ref().map_or(DEFAULT_HYPH_LANG, String::as_str))
- .and_then(|lang| HYPHENATION_PATTERNS.get(&lang))
- } else {
- None
- };
-
- items = self.hyphenate_paragraph(dictionary, items, &mut hyph_indices);
- bps = total_fit(&items, &line_lengths, stretch_tolerance, 0);
+ if bps.is_empty() && style.text_align != TextAlign::Center {
+ if let Some(dictionary) = hyph_lang(style.language.as_ref().map_or(DEFAULT_HYPH_LANG, String::as_str))
+ .and_then(|lang| HYPHENATION_PATTERNS.get(&lang)) {
+ items = self.hyphenate_paragraph(style, dictionary, items, &mut hyph_indices);
+ bps = total_fit(&items, &line_lengths, self.stretch_tolerance, 0);
+ }
}
if bps.is_empty() {
- bps = standard_fit(&items, &line_lengths, stretch_tolerance);
+ bps = standard_fit(&items, &line_lengths, self.stretch_tolerance);
}
if bps.is_empty() {
@@ -1495,69 +1494,72 @@ impl Engine {
}
}
- fn hyphenate_paragraph(&mut self, dictionary: Option<&Standard>, items: Vec>, hyph_indices: &mut Vec<[usize; 2]>) -> Vec> {
+ fn hyphenate_paragraph(&mut self, style: &StyleData, dictionary: &Standard, items: Vec>, hyph_indices: &mut Vec<[usize; 2]>) -> Vec> {
let mut hyph_items = Vec::with_capacity(items.len());
for itm in items {
match itm {
ParagraphItem::Box { data: ParagraphElement::Text(ref element), .. } => {
let text = &element.text;
- let hyphen_width = if dictionary.is_some() {
+ let (hyphen_width, stretch) = {
let font = self.fonts.as_mut().unwrap()
.get_mut(element.font_kind, element.font_style, element.font_weight);
font.set_size(element.font_size, self.dpi);
- font.plan("-", None, element.font_features.as_deref()).width
- } else {
- 0
+ let plan = font.plan(" -", None, element.font_features.as_deref());
+ (plan.glyph_advance(1), 3 * plan.glyph_advance(0))
};
- if let Some(dict) = dictionary {
- let mut index_before = text.find(char::is_alphabetic).unwrap_or_else(|| text.len());
- if index_before > 0 {
- let subelem = self.box_from_chunk(&text[0..index_before],
- 0,
+ let mut index_before = text.find(char::is_alphabetic).unwrap_or_else(|| text.len());
+ if index_before > 0 {
+ let subelem = self.box_from_chunk(&text[0..index_before],
+ 0,
+ element);
+ hyph_items.push(subelem);
+ }
+
+ let mut index_after = text[index_before..].find(|c: char| !c.is_alphabetic())
+ .map(|i| index_before + i)
+ .unwrap_or_else(|| text.len());
+ while index_before < index_after {
+ let mut index = 0;
+ let chunk = &text[index_before..index_after];
+ let len_before = hyph_items.len();
+
+ for segment in dictionary.hyphenate(chunk).iter().segments() {
+ let subelem = self.box_from_chunk(segment,
+ index_before + index,
element);
hyph_items.push(subelem);
- }
-
- let mut index_after = text[index_before..].find(|c: char| !c.is_alphabetic())
- .map(|i| index_before + i)
- .unwrap_or_else(|| text.len());
- while index_before < index_after {
- let mut index = 0;
- let chunk = &text[index_before..index_after];
- let len_before = hyph_items.len();
- for segment in dict.hyphenate(chunk).iter().segments() {
- let subelem = self.box_from_chunk(segment,
- index_before + index,
- element);
- hyph_items.push(subelem);
- index += segment.len();
- if index < chunk.len() {
+ index += segment.len();
+ if index < chunk.len() {
+ if style.text_align == TextAlign::Justify {
hyph_items.push(ParagraphItem::Penalty { width: hyphen_width, penalty: self.hyphen_penalty, flagged: true });
+ } else {
+ hyph_items.push(ParagraphItem::Penalty { width: 0, penalty: INFINITE_PENALTY, flagged: false });
+ hyph_items.push(ParagraphItem::Glue { width: 0, stretch, shrink: 0 });
+ hyph_items.push(ParagraphItem::Penalty { width: hyphen_width, penalty: 10*self.hyphen_penalty, flagged: true });
+ hyph_items.push(ParagraphItem::Glue { width: 0, stretch: -stretch, shrink: 0 });
}
}
- let len_after = hyph_items.len();
- if len_after > 1 + len_before {
- hyph_indices.push([len_before, len_after]);
- }
- index_before = text[index_after..].find(char::is_alphabetic)
- .map(|i| index_after + i)
- .unwrap_or_else(|| text.len());
- if index_before > index_after {
- let subelem = self.box_from_chunk(&text[index_after..index_before],
- index_after,
- &element);
- hyph_items.push(subelem);
- }
+ }
- index_after = text[index_before..].find(|c: char| !c.is_alphabetic())
- .map(|i| index_before + i)
- .unwrap_or_else(|| text.len());
+ let len_after = hyph_items.len();
+ if len_after > 1 + len_before {
+ hyph_indices.push([len_before, len_after]);
}
- } else {
- let subelem = self.box_from_chunk(text, 0, element);
- hyph_items.push(subelem);
+ index_before = text[index_after..].find(char::is_alphabetic)
+ .map(|i| index_after + i)
+ .unwrap_or_else(|| text.len());
+ if index_before > index_after {
+ let subelem = self.box_from_chunk(&text[index_after..index_before],
+ index_after,
+ &element);
+ hyph_items.push(subelem);
+ }
+
+ index_after = text[index_before..].find(|c: char| !c.is_alphabetic())
+ .map(|i| index_before + i)
+ .unwrap_or_else(|| text.len());
}
},
_ => { hyph_items.push(itm) },
@@ -1612,7 +1614,13 @@ impl Engine {
line_stats = LineStats::default();
merged_items.push(itm);
+ if i >= start_index && i < end_index {
+ start_index = i + 1;
+ }
} else if i >= start_index && i < end_index {
+ if i > start_index {
+ index_drift += 1;
+ }
if let ParagraphItem::Box { width, data } = itm {
match merged_element {
ParagraphElement::Text(TextElement { ref mut text, .. }) => {
@@ -1627,8 +1635,6 @@ impl Engine {
if !line_stats.started {
line_stats.started = true;
}
- } else {
- index_drift += 2;
}
if i == end_index - 1 {
j += 1;