mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Make chinese justification less bad
This commit is contained in:
parent
3d52387eea
commit
eb22eed31b
@ -310,15 +310,15 @@ impl<'a> Line<'a> {
|
||||
self.items().nth(index)
|
||||
}
|
||||
|
||||
// How many spaces the line contains.
|
||||
fn spaces(&self) -> usize {
|
||||
let mut spaces = 0;
|
||||
// How many justifiable glyphs the line contains.
|
||||
fn justifiables(&self) -> usize {
|
||||
let mut count = 0;
|
||||
for item in self.items() {
|
||||
if let ParItem::Text(shaped) = item {
|
||||
spaces += shaped.spaces();
|
||||
count += shaped.justifiables();
|
||||
}
|
||||
}
|
||||
spaces
|
||||
count
|
||||
}
|
||||
|
||||
/// How much of the line is stretchable spaces.
|
||||
@ -509,11 +509,11 @@ fn linebreak_optimized<'a>(
|
||||
// Cost parameters.
|
||||
const HYPH_COST: Cost = 0.5;
|
||||
const CONSECUTIVE_DASH_COST: Cost = 30.0;
|
||||
const MAX_COST: Cost = 10_000.0;
|
||||
const MAX_COST: Cost = 1_000_000.0;
|
||||
const MIN_COST: Cost = -MAX_COST;
|
||||
const MIN_RATIO: f64 = -0.15;
|
||||
|
||||
// Density parameters.
|
||||
let em = styles.get(TextNode::SIZE);
|
||||
let justify = styles.get(ParNode::JUSTIFY);
|
||||
|
||||
// Dynamic programming table.
|
||||
@ -537,11 +537,15 @@ fn linebreak_optimized<'a>(
|
||||
|
||||
// Determine how much the line's spaces would need to be stretched
|
||||
// to make it the desired width.
|
||||
let mut ratio = (width - attempt.size.x) / attempt.stretch();
|
||||
let delta = width - attempt.size.x;
|
||||
let mut ratio = delta / attempt.stretch();
|
||||
if ratio.is_infinite() {
|
||||
ratio = ratio.signum() * MAX_COST;
|
||||
ratio = delta / (em / 2.0);
|
||||
}
|
||||
|
||||
// At some point, it doesn't matter any more.
|
||||
ratio = ratio.min(10.0);
|
||||
|
||||
// Determine the cost of the line.
|
||||
let mut cost = if ratio < if justify { MIN_RATIO } else { 0.0 } {
|
||||
// The line is overfull. This is the case if
|
||||
@ -863,9 +867,9 @@ fn commit(
|
||||
&& line.range.end < line.bidi.text.len()
|
||||
&& line.fr.is_zero())
|
||||
{
|
||||
let spaces = line.spaces();
|
||||
if spaces > 0 {
|
||||
justification = remaining / spaces as f64;
|
||||
let justifiables = line.justifiables();
|
||||
if justifiables > 0 {
|
||||
justification = remaining / justifiables as f64;
|
||||
remaining = Length::zero();
|
||||
}
|
||||
}
|
||||
|
@ -50,10 +50,15 @@ pub struct ShapedGlyph {
|
||||
}
|
||||
|
||||
impl ShapedGlyph {
|
||||
/// Whether the glyph is a justifiable space.
|
||||
/// Whether the glyph is a space.
|
||||
pub fn is_space(&self) -> bool {
|
||||
self.c == ' '
|
||||
}
|
||||
|
||||
/// Whether the glyph is justifiable.
|
||||
pub fn is_justifiable(&self) -> bool {
|
||||
matches!(self.c, ' ' | ',' | ' ' | '。' | '、')
|
||||
}
|
||||
}
|
||||
|
||||
/// A side you can go toward.
|
||||
@ -68,7 +73,7 @@ impl<'a> ShapedText<'a> {
|
||||
/// Build the shaped text's frame.
|
||||
///
|
||||
/// The `justification` defines how much extra advance width each
|
||||
/// [space glyph](ShapedGlyph::is_space) will get.
|
||||
/// [justifiable glyph](ShapedGlyph::is_justifiable) will get.
|
||||
pub fn build(&self, fonts: &FontStore, justification: Length) -> Frame {
|
||||
let mut offset = Length::zero();
|
||||
let mut frame = Frame::new(self.size);
|
||||
@ -84,7 +89,7 @@ impl<'a> ShapedText<'a> {
|
||||
.map(|glyph| Glyph {
|
||||
id: glyph.glyph_id,
|
||||
x_advance: glyph.x_advance
|
||||
+ if glyph.is_space() {
|
||||
+ if glyph.is_justifiable() {
|
||||
frame.size.x += justification;
|
||||
Em::from_length(justification, size)
|
||||
} else {
|
||||
@ -115,16 +120,16 @@ impl<'a> ShapedText<'a> {
|
||||
frame
|
||||
}
|
||||
|
||||
/// How many spaces the text contains.
|
||||
pub fn spaces(&self) -> usize {
|
||||
self.glyphs.iter().filter(|g| g.is_space()).count()
|
||||
/// How many justifiable glyphs the text contains.
|
||||
pub fn justifiables(&self) -> usize {
|
||||
self.glyphs.iter().filter(|g| g.is_justifiable()).count()
|
||||
}
|
||||
|
||||
/// The width of the spaces in the text.
|
||||
pub fn stretch(&self) -> Length {
|
||||
self.glyphs
|
||||
.iter()
|
||||
.filter(|g| g.is_space())
|
||||
.filter(|g| g.is_justifiable())
|
||||
.map(|g| g.x_advance)
|
||||
.sum::<Em>()
|
||||
.resolve(self.styles.get(TextNode::SIZE))
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 28 KiB |
@ -19,3 +19,9 @@ First line indents and hyphenation play nicely with justified text.
|
||||
#set par(justify: true)
|
||||
A B C \
|
||||
D
|
||||
|
||||
---
|
||||
// Test that justificating chinese text is at least a bit sensible.
|
||||
#set page(width: 200pt)
|
||||
#set par(justify: true)
|
||||
中文维基百科使用汉字书写,汉字是汉族或华人的共同文字,是中国大陆、新加坡、马来西亚、台湾、香港、澳门的唯一官方文字或官方文字之一。25.9%,而美国和荷兰则分別占13.7%及8.2%。近年來,中国大陆地区的维基百科编辑者正在迅速增加;
|
||||
|
Loading…
x
Reference in New Issue
Block a user