Skip to content
This repository has been archived by the owner on Nov 26, 2024. It is now read-only.

Commit

Permalink
#58 wip very very basic linebreak
Browse files Browse the repository at this point in the history
  • Loading branch information
bennobuilder committed Mar 20, 2024
1 parent f9c4a89 commit 91a7d11
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 29 deletions.
73 changes: 48 additions & 25 deletions crates/attributed_string/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use token::{Token, TokenVariant};
use unicode_linebreak::BreakClass;
use usvg::{
database::FontsCache,
process_anchor,
text::{TextAnchor, TextFlow, WritingMode},
};

Expand Down Expand Up @@ -77,14 +76,18 @@ impl AttributedString {
let break_class = unicode_linebreak::break_property(*_char as u32);

match break_class {
BreakClass::Mandatory | BreakClass::LineFeed | BreakClass::CarriageReturn => {
BreakClass::Mandatory
| BreakClass::LineFeed
| BreakClass::NextLine
| BreakClass::CarriageReturn => {
// Add text fragment token
if start != index {
// Add text fragment token
token_stream.push(Token::new(
TokenVariant::TextFragment,
Range { start, end: index },
));
}

// Add line break token
token_stream.push(Token::new(
TokenVariant::Linebreak,
Expand All @@ -96,13 +99,14 @@ impl AttributedString {
start = index + 1;
}
BreakClass::Space | BreakClass::ZeroWidthSpace => {
// Add text fragment token
if start != index {
// Add text fragment token
token_stream.push(Token::new(
TokenVariant::TextFragment,
Range { start, end: index },
));
}

// Add word separator token
token_stream.push(Token::new(
TokenVariant::WordSeparator,
Expand Down Expand Up @@ -166,17 +170,48 @@ impl AttributedString {
}
}

// TODO: Apply linebreaks
fn resolve_clusters_positions_horizontal(&mut self) {
let mut x = process_anchor(
self.anchor,
self.token_stream
.iter()
.fold(0.0, |acc, token| acc + token.clusers_length()),
);
let y = 0.0;

// let mut x = process_anchor(
// self.anchor,
// self.token_stream
// .iter()
// .fold(0.0, |acc, token| acc + token.get_advance()),
// );
let mut x = 0.0;
let mut y = 0.0;

let mut current_width = 0.0;
let mut current_line_height = 0.0;
for token in self.token_stream.iter_mut() {
let token_width = token.get_advance();
let token_height = token.get_max_height();

let force_break = match token.variant {
TokenVariant::Linebreak => true,
_ => false,
};
let will_wrap = current_width + token_width > self.width || force_break;

if will_wrap {
let ignore = match token.variant {
TokenVariant::Linebreak => true,
TokenVariant::WordSeparator => true,
_ => false,
};

y += current_line_height;
current_width = if ignore { 0.0 } else { token_width };
current_line_height = if ignore { 0.0 } else { token_height };
} else {
current_width += token_width;
if token_height > current_line_height {
current_line_height = token_height;
}
}

x = current_width - token_width;

// Position clusters of token
for cluster in token.outlined_clusters.iter_mut() {
cluster.transform = cluster.transform.pre_translate(x, y);
x += cluster.advance;
Expand Down Expand Up @@ -215,18 +250,6 @@ impl AttributedString {
}
}

// https://www.w3.org/TR/css-text-3/#word-separator
pub fn is_word_separator_char(c: char) -> bool {
matches!(
c as u32,
0x0020 | 0x00A0 | 0x1361 | 0x010100 | 0x010101 | 0x01039F | 0x01091F
)
}

pub fn is_linebreak_char(c: char) -> bool {
matches!(c, '\n')
}

#[cfg(test)]
mod tests {
use self::usvg::text::{FontFamily, FontStretch, FontStyle};
Expand Down
14 changes: 11 additions & 3 deletions crates/attributed_string/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::{
font::resolve_font_from_cache,
usvg::{
byte_index::ByteIndex,
clusters_length,
database::FontsCache,
glyph::{Glyph, GlyphClusters},
outline_cluster,
Expand All @@ -24,6 +23,7 @@ pub struct Token {
pub variant: TokenVariant,
/// Byte range in the original text marking the token's start and end indices.
/// Enables attribute identification and position tracking.
/// Inclusive start, exclusive of stop (start <= x < end).
pub range: Range<usize>,
///
pub outlined_clusters: Vec<OutlinedCluster>,
Expand All @@ -38,8 +38,16 @@ impl Token {
}
}

pub fn clusers_length(&self) -> f32 {
clusters_length(&self.outlined_clusters)
pub fn get_advance(&self) -> f32 {
self.outlined_clusters
.iter()
.fold(0.0, |acc, oc| acc + oc.advance)
}

pub fn get_max_height(&self) -> f32 {
self.outlined_clusters
.iter()
.fold(0.0, |acc, oc| acc.max(oc.height()))
}

// TODO: Does it make more sense to shape the glyphs from the attribute intervals
Expand Down
2 changes: 1 addition & 1 deletion crates/attributed_string/src/usvg/outlined_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub struct OutlinedCluster {
}

impl OutlinedCluster {
fn height(&self) -> f32 {
pub fn height(&self) -> f32 {
self.ascent - self.descent
}
}

0 comments on commit 91a7d11

Please sign in to comment.