mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +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)
|
self.items().nth(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// How many spaces the line contains.
|
// How many justifiable glyphs the line contains.
|
||||||
fn spaces(&self) -> usize {
|
fn justifiables(&self) -> usize {
|
||||||
let mut spaces = 0;
|
let mut count = 0;
|
||||||
for item in self.items() {
|
for item in self.items() {
|
||||||
if let ParItem::Text(shaped) = item {
|
if let ParItem::Text(shaped) = item {
|
||||||
spaces += shaped.spaces();
|
count += shaped.justifiables();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spaces
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How much of the line is stretchable spaces.
|
/// How much of the line is stretchable spaces.
|
||||||
@ -509,11 +509,11 @@ fn linebreak_optimized<'a>(
|
|||||||
// Cost parameters.
|
// Cost parameters.
|
||||||
const HYPH_COST: Cost = 0.5;
|
const HYPH_COST: Cost = 0.5;
|
||||||
const CONSECUTIVE_DASH_COST: Cost = 30.0;
|
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_COST: Cost = -MAX_COST;
|
||||||
const MIN_RATIO: f64 = -0.15;
|
const MIN_RATIO: f64 = -0.15;
|
||||||
|
|
||||||
// Density parameters.
|
let em = styles.get(TextNode::SIZE);
|
||||||
let justify = styles.get(ParNode::JUSTIFY);
|
let justify = styles.get(ParNode::JUSTIFY);
|
||||||
|
|
||||||
// Dynamic programming table.
|
// Dynamic programming table.
|
||||||
@ -537,11 +537,15 @@ fn linebreak_optimized<'a>(
|
|||||||
|
|
||||||
// Determine how much the line's spaces would need to be stretched
|
// Determine how much the line's spaces would need to be stretched
|
||||||
// to make it the desired width.
|
// 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() {
|
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.
|
// Determine the cost of the line.
|
||||||
let mut cost = if ratio < if justify { MIN_RATIO } else { 0.0 } {
|
let mut cost = if ratio < if justify { MIN_RATIO } else { 0.0 } {
|
||||||
// The line is overfull. This is the case if
|
// The line is overfull. This is the case if
|
||||||
@ -863,9 +867,9 @@ fn commit(
|
|||||||
&& line.range.end < line.bidi.text.len()
|
&& line.range.end < line.bidi.text.len()
|
||||||
&& line.fr.is_zero())
|
&& line.fr.is_zero())
|
||||||
{
|
{
|
||||||
let spaces = line.spaces();
|
let justifiables = line.justifiables();
|
||||||
if spaces > 0 {
|
if justifiables > 0 {
|
||||||
justification = remaining / spaces as f64;
|
justification = remaining / justifiables as f64;
|
||||||
remaining = Length::zero();
|
remaining = Length::zero();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,15 @@ pub struct ShapedGlyph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ShapedGlyph {
|
impl ShapedGlyph {
|
||||||
/// Whether the glyph is a justifiable space.
|
/// Whether the glyph is a space.
|
||||||
pub fn is_space(&self) -> bool {
|
pub fn is_space(&self) -> bool {
|
||||||
self.c == ' '
|
self.c == ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the glyph is justifiable.
|
||||||
|
pub fn is_justifiable(&self) -> bool {
|
||||||
|
matches!(self.c, ' ' | ',' | ' ' | '。' | '、')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A side you can go toward.
|
/// A side you can go toward.
|
||||||
@ -68,7 +73,7 @@ impl<'a> ShapedText<'a> {
|
|||||||
/// Build the shaped text's frame.
|
/// Build the shaped text's frame.
|
||||||
///
|
///
|
||||||
/// The `justification` defines how much extra advance width each
|
/// 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 {
|
pub fn build(&self, fonts: &FontStore, justification: Length) -> Frame {
|
||||||
let mut offset = Length::zero();
|
let mut offset = Length::zero();
|
||||||
let mut frame = Frame::new(self.size);
|
let mut frame = Frame::new(self.size);
|
||||||
@ -84,7 +89,7 @@ impl<'a> ShapedText<'a> {
|
|||||||
.map(|glyph| Glyph {
|
.map(|glyph| Glyph {
|
||||||
id: glyph.glyph_id,
|
id: glyph.glyph_id,
|
||||||
x_advance: glyph.x_advance
|
x_advance: glyph.x_advance
|
||||||
+ if glyph.is_space() {
|
+ if glyph.is_justifiable() {
|
||||||
frame.size.x += justification;
|
frame.size.x += justification;
|
||||||
Em::from_length(justification, size)
|
Em::from_length(justification, size)
|
||||||
} else {
|
} else {
|
||||||
@ -115,16 +120,16 @@ impl<'a> ShapedText<'a> {
|
|||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How many spaces the text contains.
|
/// How many justifiable glyphs the text contains.
|
||||||
pub fn spaces(&self) -> usize {
|
pub fn justifiables(&self) -> usize {
|
||||||
self.glyphs.iter().filter(|g| g.is_space()).count()
|
self.glyphs.iter().filter(|g| g.is_justifiable()).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The width of the spaces in the text.
|
/// The width of the spaces in the text.
|
||||||
pub fn stretch(&self) -> Length {
|
pub fn stretch(&self) -> Length {
|
||||||
self.glyphs
|
self.glyphs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|g| g.is_space())
|
.filter(|g| g.is_justifiable())
|
||||||
.map(|g| g.x_advance)
|
.map(|g| g.x_advance)
|
||||||
.sum::<Em>()
|
.sum::<Em>()
|
||||||
.resolve(self.styles.get(TextNode::SIZE))
|
.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)
|
#set par(justify: true)
|
||||||
A B C \
|
A B C \
|
||||||
D
|
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