refactor: address clippy warnings and improve code quality (#409)
- Fix string formatting with modern interpolation syntax - Improve Debug implementation with finish_non_exhaustive() - Fix function placement in shape.rs to avoid items_after_statements warning - Use more idiomatic Rust patterns (map_or_else, next_back) - Clean up conditional imports in vi.rs - Convert multiple methods to `const` functions for optimization and consistency - Introduce `core_maths` for enhanced no-std compatibility - Update `Cargo.toml` for the new optional dependency and feature adjustments
This commit is contained in:
parent
e80dbc3607
commit
a2f1f4b2a0
20 changed files with 282 additions and 299 deletions
|
|
@ -11,6 +11,7 @@ rust-version = "1.75"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "2.4.1"
|
||||
core_maths = { version = "0.1.1", optional = true }
|
||||
cosmic_undo_2 = { version = "0.2.0", optional = true }
|
||||
fontdb = { version = "0.23", default-features = false }
|
||||
hashbrown = { version = "0.14.1", optional = true, default-features = false }
|
||||
|
|
@ -48,7 +49,7 @@ optional = true
|
|||
default = ["std", "swash", "fontconfig"]
|
||||
fontconfig = ["fontdb/fontconfig", "std"]
|
||||
monospace_fallback = []
|
||||
no_std = ["rustybuzz/libm", "hashbrown", "dep:libm"]
|
||||
no_std = ["rustybuzz/libm", "hashbrown", "dep:libm", "core_maths"]
|
||||
peniko = ["dep:peniko"]
|
||||
shape-run-cache = []
|
||||
std = [
|
||||
|
|
|
|||
62
src/attrs.rs
62
src/attrs.rs
|
|
@ -30,37 +30,37 @@ impl Color {
|
|||
|
||||
/// Get a tuple over all of the attributes, in `(r, g, b, a)` order.
|
||||
#[inline]
|
||||
pub fn as_rgba_tuple(self) -> (u8, u8, u8, u8) {
|
||||
pub const fn as_rgba_tuple(self) -> (u8, u8, u8, u8) {
|
||||
(self.r(), self.g(), self.b(), self.a())
|
||||
}
|
||||
|
||||
/// Get an array over all of the components, in `[r, g, b, a]` order.
|
||||
#[inline]
|
||||
pub fn as_rgba(self) -> [u8; 4] {
|
||||
pub const fn as_rgba(self) -> [u8; 4] {
|
||||
[self.r(), self.g(), self.b(), self.a()]
|
||||
}
|
||||
|
||||
/// Get the red component
|
||||
#[inline]
|
||||
pub fn r(&self) -> u8 {
|
||||
pub const fn r(&self) -> u8 {
|
||||
((self.0 & 0x00_FF_00_00) >> 16) as u8
|
||||
}
|
||||
|
||||
/// Get the green component
|
||||
#[inline]
|
||||
pub fn g(&self) -> u8 {
|
||||
pub const fn g(&self) -> u8 {
|
||||
((self.0 & 0x00_00_FF_00) >> 8) as u8
|
||||
}
|
||||
|
||||
/// Get the blue component
|
||||
#[inline]
|
||||
pub fn b(&self) -> u8 {
|
||||
pub const fn b(&self) -> u8 {
|
||||
(self.0 & 0x00_00_00_FF) as u8
|
||||
}
|
||||
|
||||
/// Get the alpha component
|
||||
#[inline]
|
||||
pub fn a(&self) -> u8 {
|
||||
pub const fn a(&self) -> u8 {
|
||||
((self.0 & 0xFF_00_00_00) >> 24) as u8
|
||||
}
|
||||
}
|
||||
|
|
@ -79,23 +79,23 @@ pub enum FamilyOwned {
|
|||
impl FamilyOwned {
|
||||
pub fn new(family: Family) -> Self {
|
||||
match family {
|
||||
Family::Name(name) => FamilyOwned::Name(SmolStr::from(name)),
|
||||
Family::Serif => FamilyOwned::Serif,
|
||||
Family::SansSerif => FamilyOwned::SansSerif,
|
||||
Family::Cursive => FamilyOwned::Cursive,
|
||||
Family::Fantasy => FamilyOwned::Fantasy,
|
||||
Family::Monospace => FamilyOwned::Monospace,
|
||||
Family::Name(name) => Self::Name(SmolStr::from(name)),
|
||||
Family::Serif => Self::Serif,
|
||||
Family::SansSerif => Self::SansSerif,
|
||||
Family::Cursive => Self::Cursive,
|
||||
Family::Fantasy => Self::Fantasy,
|
||||
Family::Monospace => Self::Monospace,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_family(&self) -> Family {
|
||||
match self {
|
||||
FamilyOwned::Name(name) => Family::Name(name),
|
||||
FamilyOwned::Serif => Family::Serif,
|
||||
FamilyOwned::SansSerif => Family::SansSerif,
|
||||
FamilyOwned::Cursive => Family::Cursive,
|
||||
FamilyOwned::Fantasy => Family::Fantasy,
|
||||
FamilyOwned::Monospace => Family::Monospace,
|
||||
Self::Name(name) => Family::Name(name),
|
||||
Self::Serif => Family::Serif,
|
||||
Self::SansSerif => Family::SansSerif,
|
||||
Self::Cursive => Family::Cursive,
|
||||
Self::Fantasy => Family::Fantasy,
|
||||
Self::Monospace => Family::Monospace,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ impl FeatureTag {
|
|||
/// Stylistic Set 2 (font-specific alternate glyphs)
|
||||
pub const STYLISTIC_SET_2: Self = Self::new(b"ss02");
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8; 4] {
|
||||
pub const fn as_bytes(&self) -> &[u8; 4] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ pub struct FontFeatures {
|
|||
}
|
||||
|
||||
impl FontFeatures {
|
||||
pub fn new() -> Self {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
features: Vec::new(),
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@ impl<'a> Attrs<'a> {
|
|||
/// Create a new set of attributes with sane defaults
|
||||
///
|
||||
/// This defaults to a regular Sans-Serif font.
|
||||
pub fn new() -> Self {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
color_opt: None,
|
||||
family: Family::SansSerif,
|
||||
|
|
@ -260,43 +260,43 @@ impl<'a> Attrs<'a> {
|
|||
}
|
||||
|
||||
/// Set [Color]
|
||||
pub fn color(mut self, color: Color) -> Self {
|
||||
pub const fn color(mut self, color: Color) -> Self {
|
||||
self.color_opt = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set [Family]
|
||||
pub fn family(mut self, family: Family<'a>) -> Self {
|
||||
pub const fn family(mut self, family: Family<'a>) -> Self {
|
||||
self.family = family;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set [Stretch]
|
||||
pub fn stretch(mut self, stretch: Stretch) -> Self {
|
||||
pub const fn stretch(mut self, stretch: Stretch) -> Self {
|
||||
self.stretch = stretch;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set [Style]
|
||||
pub fn style(mut self, style: Style) -> Self {
|
||||
pub const fn style(mut self, style: Style) -> Self {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set [Weight]
|
||||
pub fn weight(mut self, weight: Weight) -> Self {
|
||||
pub const fn weight(mut self, weight: Weight) -> Self {
|
||||
self.weight = weight;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set metadata
|
||||
pub fn metadata(mut self, metadata: usize) -> Self {
|
||||
pub const fn metadata(mut self, metadata: usize) -> Self {
|
||||
self.metadata = metadata;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set [`CacheKeyFlags`]
|
||||
pub fn cache_key_flags(mut self, cache_key_flags: CacheKeyFlags) -> Self {
|
||||
pub const fn cache_key_flags(mut self, cache_key_flags: CacheKeyFlags) -> Self {
|
||||
self.cache_key_flags = cache_key_flags;
|
||||
self
|
||||
}
|
||||
|
|
@ -308,7 +308,7 @@ impl<'a> Attrs<'a> {
|
|||
}
|
||||
|
||||
/// Set letter spacing (tracking) in EM
|
||||
pub fn letter_spacing(mut self, letter_spacing: f32) -> Self {
|
||||
pub const fn letter_spacing(mut self, letter_spacing: f32) -> Self {
|
||||
self.letter_spacing_opt = Some(LetterSpacing(letter_spacing));
|
||||
self
|
||||
}
|
||||
|
|
@ -471,7 +471,9 @@ impl AttrsList {
|
|||
for span in self.spans.iter() {
|
||||
if span.0.end <= index {
|
||||
continue;
|
||||
} else if span.0.start >= index {
|
||||
}
|
||||
|
||||
if span.0.start >= index {
|
||||
removes.push((span.0.clone(), false));
|
||||
} else {
|
||||
removes.push((span.0.clone(), true));
|
||||
|
|
|
|||
|
|
@ -63,13 +63,12 @@ impl<'text> Iterator for BidiParagraphs<'text> {
|
|||
let paragraph = &self.text[para.range];
|
||||
// `para.range` includes the newline that splits the line, so remove it if present
|
||||
let mut char_indices = paragraph.char_indices();
|
||||
if let Some(i) = char_indices.next_back().and_then(|(i, c)| {
|
||||
// `BidiClass::B` is a Paragraph_Separator (various newline characters)
|
||||
(bidi_class(c) == BidiClass::B).then_some(i)
|
||||
}) {
|
||||
Some(¶graph[0..i])
|
||||
} else {
|
||||
Some(paragraph)
|
||||
}
|
||||
char_indices
|
||||
.next_back()
|
||||
.and_then(|(i, c)| {
|
||||
// `BidiClass::B` is a Paragraph_Separator (various newline characters)
|
||||
(bidi_class(c) == BidiClass::B).then_some(i)
|
||||
})
|
||||
.map_or(Some(paragraph), |i| Some(¶graph[0..i]))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
111
src/buffer.rs
111
src/buffer.rs
|
|
@ -2,11 +2,16 @@
|
|||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
use core::{cmp, fmt};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core_maths::CoreFloat;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
#[cfg(feature = "swash")]
|
||||
use crate::Color;
|
||||
|
||||
use crate::{
|
||||
Affinity, Align, Attrs, AttrsList, BidiParagraphs, BorrowedWithFontSystem, BufferLine, Cursor,
|
||||
FontSystem, LayoutCursor, LayoutGlyph, LayoutLine, LineEnding, LineIter, Motion, Scroll,
|
||||
|
|
@ -45,36 +50,34 @@ impl LayoutRun<'_> {
|
|||
let mut x_end = None;
|
||||
let rtl_factor = if self.rtl { 1. } else { 0. };
|
||||
let ltr_factor = 1. - rtl_factor;
|
||||
for glyph in self.glyphs.iter() {
|
||||
for glyph in self.glyphs {
|
||||
let cursor = self.cursor_from_glyph_left(glyph);
|
||||
if cursor >= cursor_start && cursor <= cursor_end {
|
||||
if x_start.is_none() {
|
||||
x_start = Some(glyph.x + glyph.w * rtl_factor);
|
||||
x_start = Some(glyph.x + glyph.w.mul_add(rtl_factor, 0.0));
|
||||
}
|
||||
x_end = Some(glyph.x + glyph.w * rtl_factor);
|
||||
x_end = Some(glyph.x + glyph.w.mul_add(rtl_factor, 0.0));
|
||||
}
|
||||
let cursor = self.cursor_from_glyph_right(glyph);
|
||||
if cursor >= cursor_start && cursor <= cursor_end {
|
||||
if x_start.is_none() {
|
||||
x_start = Some(glyph.x + glyph.w * ltr_factor);
|
||||
x_start = Some(glyph.x + glyph.w.mul_add(ltr_factor, 0.0));
|
||||
}
|
||||
x_end = Some(glyph.x + glyph.w * ltr_factor);
|
||||
x_end = Some(glyph.x + glyph.w.mul_add(ltr_factor, 0.0));
|
||||
}
|
||||
}
|
||||
if let Some(x_start) = x_start {
|
||||
x_start.map(|x_start| {
|
||||
let x_end = x_end.expect("end of cursor not found");
|
||||
let (x_start, x_end) = if x_start < x_end {
|
||||
(x_start, x_end)
|
||||
} else {
|
||||
(x_end, x_start)
|
||||
};
|
||||
Some((x_start, x_end - x_start))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
(x_start, x_end - x_start)
|
||||
})
|
||||
}
|
||||
|
||||
fn cursor_from_glyph_left(&self, glyph: &LayoutGlyph) -> Cursor {
|
||||
const fn cursor_from_glyph_left(&self, glyph: &LayoutGlyph) -> Cursor {
|
||||
if self.rtl {
|
||||
Cursor::new_with_affinity(self.line_i, glyph.end, Affinity::Before)
|
||||
} else {
|
||||
|
|
@ -82,7 +85,7 @@ impl LayoutRun<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cursor_from_glyph_right(&self, glyph: &LayoutGlyph) -> Cursor {
|
||||
const fn cursor_from_glyph_right(&self, glyph: &LayoutGlyph) -> Cursor {
|
||||
if self.rtl {
|
||||
Cursor::new_with_affinity(self.line_i, glyph.start, Affinity::After)
|
||||
} else {
|
||||
|
|
@ -102,7 +105,7 @@ pub struct LayoutRunIter<'b> {
|
|||
}
|
||||
|
||||
impl<'b> LayoutRunIter<'b> {
|
||||
pub fn new(buffer: &'b Buffer) -> Self {
|
||||
pub const fn new(buffer: &'b Buffer) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
line_i: buffer.scroll.line,
|
||||
|
|
@ -276,7 +279,7 @@ impl Buffer {
|
|||
pub fn borrow_with<'a>(
|
||||
&'a mut self,
|
||||
font_system: &'a mut FontSystem,
|
||||
) -> BorrowedWithFontSystem<'a, Buffer> {
|
||||
) -> BorrowedWithFontSystem<'a, Self> {
|
||||
BorrowedWithFontSystem {
|
||||
inner: self,
|
||||
font_system,
|
||||
|
|
@ -358,7 +361,7 @@ impl Buffer {
|
|||
let layout = self
|
||||
.line_layout(font_system, line_i)
|
||||
.expect("shape_until_cursor failed to scroll forwards");
|
||||
for layout_line in layout.iter() {
|
||||
for layout_line in layout {
|
||||
total_height += layout_line.line_height_opt.unwrap_or(metrics.line_height);
|
||||
}
|
||||
if total_height > height + self.scroll.vertical {
|
||||
|
|
@ -379,18 +382,16 @@ impl Buffer {
|
|||
if let Some(layout_cursor) = self.layout_cursor(font_system, cursor) {
|
||||
if let Some(layout_lines) = self.line_layout(font_system, layout_cursor.line) {
|
||||
if let Some(layout_line) = layout_lines.get(layout_cursor.layout) {
|
||||
let (x_min, x_max) = if let Some(glyph) = layout_line
|
||||
let (x_min, x_max) = layout_line
|
||||
.glyphs
|
||||
.get(layout_cursor.glyph)
|
||||
.or_else(|| layout_line.glyphs.last())
|
||||
{
|
||||
//TODO: use code from cursor_glyph_opt?
|
||||
let x_a = glyph.x;
|
||||
let x_b = glyph.x + glyph.w;
|
||||
(x_a.min(x_b), x_a.max(x_b))
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
};
|
||||
.map_or((0.0, 0.0), |glyph| {
|
||||
//TODO: use code from cursor_glyph_opt?
|
||||
let x_a = glyph.x;
|
||||
let x_b = glyph.x + glyph.w;
|
||||
(x_a.min(x_b), x_a.max(x_b))
|
||||
});
|
||||
if x_min < self.scroll.horizontal {
|
||||
self.scroll.horizontal = x_min;
|
||||
self.redraw = true;
|
||||
|
|
@ -419,7 +420,7 @@ impl Buffer {
|
|||
let line_i = self.scroll.line - 1;
|
||||
if let Some(layout) = self.line_layout(font_system, line_i) {
|
||||
let mut layout_height = 0.0;
|
||||
for layout_line in layout.iter() {
|
||||
for layout_line in layout {
|
||||
layout_height +=
|
||||
layout_line.line_height_opt.unwrap_or(metrics.line_height);
|
||||
}
|
||||
|
|
@ -451,16 +452,15 @@ impl Buffer {
|
|||
if prune {
|
||||
self.lines[line_i].reset_shaping();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
let mut layout_height = 0.0;
|
||||
let layout = self
|
||||
.line_layout(font_system, line_i)
|
||||
.expect("shape_until_scroll invalid line");
|
||||
for layout_line in layout.iter() {
|
||||
for layout_line in layout {
|
||||
let line_height = layout_line.line_height_opt.unwrap_or(metrics.line_height);
|
||||
layout_height += line_height;
|
||||
total_height += line_height;
|
||||
|
|
@ -547,7 +547,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current [`Metrics`]
|
||||
pub fn metrics(&self) -> Metrics {
|
||||
pub const fn metrics(&self) -> Metrics {
|
||||
self.metrics
|
||||
}
|
||||
|
||||
|
|
@ -561,7 +561,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current [`Wrap`]
|
||||
pub fn wrap(&self) -> Wrap {
|
||||
pub const fn wrap(&self) -> Wrap {
|
||||
self.wrap
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +575,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current `monospace_width`
|
||||
pub fn monospace_width(&self) -> Option<f32> {
|
||||
pub const fn monospace_width(&self) -> Option<f32> {
|
||||
self.monospace_width
|
||||
}
|
||||
|
||||
|
|
@ -593,7 +593,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current `tab_width`
|
||||
pub fn tab_width(&self) -> u16 {
|
||||
pub const fn tab_width(&self) -> u16 {
|
||||
self.tab_width
|
||||
}
|
||||
|
||||
|
|
@ -606,7 +606,7 @@ impl Buffer {
|
|||
if tab_width != self.tab_width {
|
||||
self.tab_width = tab_width;
|
||||
// Shaping must be reset when tab width is changed
|
||||
for line in self.lines.iter_mut() {
|
||||
for line in &mut self.lines {
|
||||
if line.shape_opt().is_some() && line.text().contains('\t') {
|
||||
line.reset_shaping();
|
||||
}
|
||||
|
|
@ -617,7 +617,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current buffer dimensions (width, height)
|
||||
pub fn size(&self) -> (Option<f32>, Option<f32>) {
|
||||
pub const fn size(&self) -> (Option<f32>, Option<f32>) {
|
||||
(self.width_opt, self.height_opt)
|
||||
}
|
||||
|
||||
|
|
@ -660,7 +660,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current scroll location
|
||||
pub fn scroll(&self) -> Scroll {
|
||||
pub const fn scroll(&self) -> Scroll {
|
||||
self.scroll
|
||||
}
|
||||
|
||||
|
|
@ -758,8 +758,7 @@ impl Buffer {
|
|||
let mut attrs_list = self
|
||||
.lines
|
||||
.get_mut(line_count)
|
||||
.map(BufferLine::reclaim_attrs)
|
||||
.unwrap_or_else(|| AttrsList::new(&Attrs::new()))
|
||||
.map_or_else(|| AttrsList::new(&Attrs::new()), BufferLine::reclaim_attrs)
|
||||
.reset(default_attrs);
|
||||
let mut line_string = self
|
||||
.lines
|
||||
|
|
@ -811,8 +810,7 @@ impl Buffer {
|
|||
let next_attrs_list = self
|
||||
.lines
|
||||
.get_mut(line_count + 1)
|
||||
.map(BufferLine::reclaim_attrs)
|
||||
.unwrap_or_else(|| AttrsList::new(&Attrs::new()))
|
||||
.map_or_else(|| AttrsList::new(&Attrs::new()), BufferLine::reclaim_attrs)
|
||||
.reset(default_attrs);
|
||||
let next_line_string = self
|
||||
.lines
|
||||
|
|
@ -856,7 +854,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// True if a redraw is needed
|
||||
pub fn redraw(&self) -> bool {
|
||||
pub const fn redraw(&self) -> bool {
|
||||
self.redraw
|
||||
}
|
||||
|
||||
|
|
@ -866,7 +864,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the visible layout runs for rendering and other tasks
|
||||
pub fn layout_runs(&self) -> LayoutRunIter {
|
||||
pub const fn layout_runs(&self) -> LayoutRunIter {
|
||||
LayoutRunIter::new(self)
|
||||
}
|
||||
|
||||
|
|
@ -991,14 +989,16 @@ impl Buffer {
|
|||
},
|
||||
};
|
||||
|
||||
let (new_index, new_affinity) = match layout_line.glyphs.get(layout_cursor.glyph) {
|
||||
Some(glyph) => (glyph.start, Affinity::After),
|
||||
None => match layout_line.glyphs.last() {
|
||||
Some(glyph) => (glyph.end, Affinity::Before),
|
||||
//TODO: is this correct?
|
||||
None => (0, Affinity::After),
|
||||
},
|
||||
};
|
||||
let (new_index, new_affinity) =
|
||||
layout_line.glyphs.get(layout_cursor.glyph).map_or_else(
|
||||
|| {
|
||||
layout_line
|
||||
.glyphs
|
||||
.last()
|
||||
.map_or((0, Affinity::After), |glyph| (glyph.end, Affinity::Before))
|
||||
},
|
||||
|glyph| (glyph.start, Affinity::After),
|
||||
);
|
||||
|
||||
if cursor.line != layout_cursor.line
|
||||
|| cursor.index != new_index
|
||||
|
|
@ -1159,8 +1159,7 @@ impl Buffer {
|
|||
cursor.index = line
|
||||
.text()
|
||||
.char_indices()
|
||||
.filter_map(|(i, c)| if c.is_whitespace() { None } else { Some(i) })
|
||||
.next()
|
||||
.find_map(|(i, c)| if c.is_whitespace() { None } else { Some(i) })
|
||||
.unwrap_or(0);
|
||||
cursor_x_opt = None;
|
||||
}
|
||||
|
|
@ -1253,7 +1252,7 @@ impl Buffer {
|
|||
.unicode_word_indices()
|
||||
.map(|(i, word)| i + word.len())
|
||||
.find(|&i| i > cursor.index)
|
||||
.unwrap_or(line.text().len());
|
||||
.unwrap_or_else(|| line.text().len());
|
||||
} else if cursor.line + 1 < self.lines.len() {
|
||||
cursor.line += 1;
|
||||
cursor.index = 0;
|
||||
|
|
@ -1340,13 +1339,9 @@ impl Buffer {
|
|||
F: FnMut(i32, i32, u32, u32, Color),
|
||||
{
|
||||
for run in self.layout_runs() {
|
||||
for glyph in run.glyphs.iter() {
|
||||
for glyph in run.glyphs {
|
||||
let physical_glyph = glyph.physical((0., 0.), 1.0);
|
||||
|
||||
let glyph_color = match glyph.color_opt {
|
||||
Some(some) => some,
|
||||
None => color,
|
||||
};
|
||||
let glyph_color = glyph.color_opt.map_or(color, |some| some);
|
||||
|
||||
cache.with_pixels(
|
||||
font_system,
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl BufferLine {
|
|||
}
|
||||
|
||||
/// Get line ending
|
||||
pub fn ending(&self) -> LineEnding {
|
||||
pub const fn ending(&self) -> LineEnding {
|
||||
self.ending
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ impl BufferLine {
|
|||
}
|
||||
|
||||
/// Get attributes list
|
||||
pub fn attrs_list(&self) -> &AttrsList {
|
||||
pub const fn attrs_list(&self) -> &AttrsList {
|
||||
&self.attrs_list
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ impl BufferLine {
|
|||
}
|
||||
|
||||
/// Get the Text alignment
|
||||
pub fn align(&self) -> Option<Align> {
|
||||
pub const fn align(&self) -> Option<Align> {
|
||||
self.align
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ impl BufferLine {
|
|||
/// Append line at end of this line
|
||||
///
|
||||
/// The wrap setting of the appended line will be lost
|
||||
pub fn append(&mut self, other: Self) {
|
||||
pub fn append(&mut self, other: &Self) {
|
||||
let len = self.text.len();
|
||||
self.text.push_str(other.text());
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ impl BufferLine {
|
|||
}
|
||||
|
||||
/// Get line shaping cache
|
||||
pub fn shape_opt(&self) -> Option<&ShapeLine> {
|
||||
pub const fn shape_opt(&self) -> Option<&ShapeLine> {
|
||||
self.shape_opt.get()
|
||||
}
|
||||
|
||||
|
|
@ -261,13 +261,13 @@ impl BufferLine {
|
|||
}
|
||||
|
||||
/// Get line layout cache
|
||||
pub fn layout_opt(&self) -> Option<&Vec<LayoutLine>> {
|
||||
pub const fn layout_opt(&self) -> Option<&Vec<LayoutLine>> {
|
||||
self.layout_opt.get()
|
||||
}
|
||||
|
||||
/// Get line metadata. This will be None if [`BufferLine::set_metadata`] has not been called
|
||||
/// after the last reset of shaping and layout caches
|
||||
pub fn metadata(&self) -> Option<usize> {
|
||||
pub const fn metadata(&self) -> Option<usize> {
|
||||
self.metadata
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub enum Cached<T: Clone + Debug> {
|
|||
|
||||
impl<T: Clone + Debug> Cached<T> {
|
||||
/// Gets the value if in state `Self::Used`.
|
||||
pub fn get(&self) -> Option<&T> {
|
||||
pub const fn get(&self) -> Option<&T> {
|
||||
match self {
|
||||
Self::Empty | Self::Unused(_) => None,
|
||||
Self::Used(t) => Some(t),
|
||||
|
|
@ -27,7 +27,7 @@ impl<T: Clone + Debug> Cached<T> {
|
|||
}
|
||||
|
||||
/// Checks if the value is empty or unused.
|
||||
pub fn is_unused(&self) -> bool {
|
||||
pub const fn is_unused(&self) -> bool {
|
||||
match self {
|
||||
Self::Empty | Self::Unused(_) => true,
|
||||
Self::Used(_) => false,
|
||||
|
|
@ -35,7 +35,7 @@ impl<T: Clone + Debug> Cached<T> {
|
|||
}
|
||||
|
||||
/// Checks if the value is used (i.e. cached for access).
|
||||
pub fn is_used(&self) -> bool {
|
||||
pub const fn is_used(&self) -> bool {
|
||||
match self {
|
||||
Self::Empty | Self::Unused(_) => false,
|
||||
Self::Used(_) => true,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl Affinity {
|
|||
*self == Self::After
|
||||
}
|
||||
|
||||
pub fn from_before(before: bool) -> Self {
|
||||
pub const fn from_before(before: bool) -> Self {
|
||||
if before {
|
||||
Self::Before
|
||||
} else {
|
||||
|
|
@ -51,7 +51,7 @@ impl Affinity {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_after(after: bool) -> Self {
|
||||
pub const fn from_after(after: bool) -> Self {
|
||||
if after {
|
||||
Self::After
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,24 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(feature = "swash")]
|
||||
use std::cmp;
|
||||
|
||||
use core::iter::once;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
#[cfg(feature = "swash")]
|
||||
use crate::Color;
|
||||
use crate::{
|
||||
Action, Attrs, AttrsList, BorrowedWithFontSystem, BufferLine, BufferRef, Change, ChangeItem,
|
||||
Cursor, Edit, FontSystem, LayoutRun, Selection, Shaping,
|
||||
};
|
||||
#[cfg(feature = "no_std")]
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
#[cfg(feature = "swash")]
|
||||
use std::cmp;
|
||||
|
||||
use core::iter::once;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
/// A wrapper of [`Buffer`] for easy editing
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Editor<'buffer> {
|
||||
|
|
@ -66,30 +69,24 @@ fn cursor_glyph_opt(cursor: &Cursor, run: &LayoutRun) -> Option<(usize, f32)> {
|
|||
|
||||
fn cursor_position(cursor: &Cursor, run: &LayoutRun) -> Option<(i32, i32)> {
|
||||
let (cursor_glyph, cursor_glyph_offset) = cursor_glyph_opt(cursor, run)?;
|
||||
let x = match run.glyphs.get(cursor_glyph) {
|
||||
Some(glyph) => {
|
||||
// Start of detected glyph
|
||||
if glyph.level.is_rtl() {
|
||||
(glyph.x + glyph.w - cursor_glyph_offset) as i32
|
||||
} else {
|
||||
(glyph.x + cursor_glyph_offset) as i32
|
||||
}
|
||||
}
|
||||
None => match run.glyphs.last() {
|
||||
Some(glyph) => {
|
||||
// End of last glyph
|
||||
let x = run.glyphs.get(cursor_glyph).map_or_else(
|
||||
|| {
|
||||
run.glyphs.last().map_or(0, |glyph| {
|
||||
if glyph.level.is_rtl() {
|
||||
glyph.x as i32
|
||||
} else {
|
||||
(glyph.x + glyph.w) as i32
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Start of empty line
|
||||
0
|
||||
})
|
||||
},
|
||||
|glyph| {
|
||||
if glyph.level.is_rtl() {
|
||||
(glyph.x + glyph.w - cursor_glyph_offset) as i32
|
||||
} else {
|
||||
(glyph.x + cursor_glyph_offset) as i32
|
||||
}
|
||||
},
|
||||
};
|
||||
);
|
||||
|
||||
Some((x, run.line_top as i32))
|
||||
}
|
||||
|
|
@ -135,7 +132,7 @@ impl<'buffer> Editor<'buffer> {
|
|||
if let Some((start, end)) = selection_bounds {
|
||||
if line_i >= start.line && line_i <= end.line {
|
||||
let mut range_opt = None;
|
||||
for glyph in run.glyphs.iter() {
|
||||
for glyph in run.glyphs {
|
||||
// Guess x offset based on characters
|
||||
let cluster = &run.text[glyph.start..glyph.end];
|
||||
let total = cluster.grapheme_indices(true).count();
|
||||
|
|
@ -197,13 +194,10 @@ impl<'buffer> Editor<'buffer> {
|
|||
f(x, y, 1, line_height as u32, cursor_color);
|
||||
}
|
||||
|
||||
for glyph in run.glyphs.iter() {
|
||||
for glyph in run.glyphs {
|
||||
let physical_glyph = glyph.physical((0., 0.), 1.0);
|
||||
|
||||
let mut glyph_color = match glyph.color_opt {
|
||||
Some(some) => some,
|
||||
None => text_color,
|
||||
};
|
||||
let mut glyph_color = glyph.color_opt.map_or(text_color, |some| some);
|
||||
if text_color != selected_text_color {
|
||||
if let Some((start, end)) = selection_bounds {
|
||||
if line_i >= start.line
|
||||
|
|
@ -277,7 +271,7 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
}
|
||||
|
||||
fn tab_width(&self) -> u16 {
|
||||
self.with_buffer(|buffer| buffer.tab_width())
|
||||
self.with_buffer(super::super::buffer::Buffer::tab_width)
|
||||
}
|
||||
|
||||
fn set_tab_width(&mut self, font_system: &mut FontSystem, tab_width: u16) {
|
||||
|
|
@ -334,12 +328,12 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
|
||||
// Re-add part of line after selection
|
||||
if let Some(after) = after_opt {
|
||||
buffer.lines[start.line].append(after);
|
||||
buffer.lines[start.line].append(&after);
|
||||
}
|
||||
|
||||
// Re-add valid parts of end line
|
||||
if let Some(end_line) = end_line_opt {
|
||||
buffer.lines[start.line].append(end_line);
|
||||
buffer.lines[start.line].append(&end_line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +370,7 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
let ending = buffer
|
||||
.lines
|
||||
.last()
|
||||
.map(|line| line.ending())
|
||||
.map(super::super::buffer_line::BufferLine::ending)
|
||||
.unwrap_or_default();
|
||||
let line = BufferLine::new(
|
||||
String::new(),
|
||||
|
|
@ -386,7 +380,7 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
buffer
|
||||
.lines
|
||||
.last()
|
||||
.map_or(Attrs::new(), |line| line.attrs_list().defaults())
|
||||
.map_or_else(Attrs::new, |line| line.attrs_list().defaults())
|
||||
},
|
||||
|x| x.defaults(),
|
||||
)),
|
||||
|
|
@ -417,7 +411,7 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
let mut these_attrs = final_attrs.split_off(data_line.len());
|
||||
remaining_split_len -= data_line.len();
|
||||
core::mem::swap(&mut these_attrs, &mut final_attrs);
|
||||
line.append(BufferLine::new(
|
||||
line.append(&BufferLine::new(
|
||||
data_line
|
||||
.strip_suffix(char::is_control)
|
||||
.unwrap_or(data_line),
|
||||
|
|
@ -438,11 +432,11 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
final_attrs.split_off(remaining_split_len),
|
||||
Shaping::Advanced,
|
||||
);
|
||||
tmp.append(after);
|
||||
tmp.append(&after);
|
||||
buffer.lines.insert(insert_line, tmp);
|
||||
cursor.line += 1;
|
||||
} else {
|
||||
line.append(after);
|
||||
line.append(&after);
|
||||
}
|
||||
for data_line in lines_iter.rev() {
|
||||
remaining_split_len -= data_line.len();
|
||||
|
|
@ -510,9 +504,8 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
}
|
||||
|
||||
fn delete_selection(&mut self) -> bool {
|
||||
let (start, end) = match self.selection_bounds() {
|
||||
Some(some) => some,
|
||||
None => return false,
|
||||
let Some((start, end)) = self.selection_bounds() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Reset cursor to start of selection
|
||||
|
|
@ -538,7 +531,7 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> {
|
|||
}
|
||||
}
|
||||
|
||||
for item in change.items.iter() {
|
||||
for item in &change.items {
|
||||
//TODO: edit cursor if needed?
|
||||
if item.insert {
|
||||
self.cursor = self.insert_at(item.start, &item.text, None);
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ impl Change {
|
|||
// Reverse change (in place)
|
||||
pub fn reverse(&mut self) {
|
||||
self.items.reverse();
|
||||
for item in self.items.iter_mut() {
|
||||
for item in &mut self.items {
|
||||
item.reverse();
|
||||
}
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ pub trait Edit<'buffer> {
|
|||
|
||||
/// Get the [`Buffer`] redraw flag
|
||||
fn redraw(&self) -> bool {
|
||||
self.with_buffer(|buffer| buffer.redraw())
|
||||
self.with_buffer(super::buffer::Buffer::redraw)
|
||||
}
|
||||
|
||||
/// Set the [`Buffer`] redraw flag
|
||||
|
|
@ -273,7 +273,7 @@ pub trait Edit<'buffer> {
|
|||
.unicode_word_indices()
|
||||
.map(|(i, word)| i + word.len())
|
||||
.find(|&i| i > end.index)
|
||||
.unwrap_or(line.text().len());
|
||||
.unwrap_or_else(|| line.text().len());
|
||||
}
|
||||
|
||||
Some((start, end))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#[cfg(feature = "no_std")]
|
||||
use core::cmp;
|
||||
|
||||
use alloc::{collections::BTreeMap, string::String};
|
||||
#[cfg(feature = "swash")]
|
||||
use core::cmp;
|
||||
use modit::{Event, Key, Parser, TextObject, WordIter};
|
||||
|
||||
use crate::{
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub trait Fallback: Send + Sync {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct Fallbacks {
|
||||
pub struct Fallbacks {
|
||||
lists: Vec<&'static str>,
|
||||
common_fallback_range: Range<usize>,
|
||||
forbidden_fallback_range: Range<usize>,
|
||||
|
|
@ -174,13 +174,14 @@ use log::warn as missing_warn;
|
|||
// Default font gets None for both `weight_offset` and `script_non_matches`, and thus, it is
|
||||
// always the first to be popped from the set.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) struct MonospaceFallbackInfo {
|
||||
pub struct MonospaceFallbackInfo {
|
||||
font_weight_diff: Option<u16>,
|
||||
codepoint_non_matches: Option<usize>,
|
||||
font_weight: u16,
|
||||
id: fontdb::ID,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FontFallbackIter<'a> {
|
||||
font_system: &'a mut FontSystem,
|
||||
font_match_keys: &'a [FontMatchKey],
|
||||
|
|
@ -223,7 +224,7 @@ impl<'a> FontFallbackIter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_missing(&mut self, word: &str) {
|
||||
pub fn check_missing(&self, word: &str) {
|
||||
if self.end {
|
||||
missing_warn!(
|
||||
"Failed to find any fallback for {:?} locale '{}': '{}'",
|
||||
|
|
@ -252,15 +253,16 @@ impl<'a> FontFallbackIter<'a> {
|
|||
}
|
||||
|
||||
pub fn face_name(&self, id: fontdb::ID) -> &str {
|
||||
if let Some(face) = self.font_system.db().face(id) {
|
||||
if let Some((name, _)) = face.families.first() {
|
||||
name
|
||||
} else {
|
||||
&face.post_script_name
|
||||
}
|
||||
} else {
|
||||
"invalid font id"
|
||||
}
|
||||
self.font_system
|
||||
.db()
|
||||
.face(id)
|
||||
.map_or("invalid font id", |face| {
|
||||
if let Some((name, _)) = face.families.first() {
|
||||
name
|
||||
} else {
|
||||
&face.post_script_name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn shape_caches(&mut self) -> &mut ShapeBuffer {
|
||||
|
|
@ -268,11 +270,10 @@ impl<'a> FontFallbackIter<'a> {
|
|||
}
|
||||
|
||||
fn face_contains_family(&self, id: fontdb::ID, family_name: &str) -> bool {
|
||||
if let Some(face) = self.font_system.db().face(id) {
|
||||
face.families.iter().any(|(name, _)| name == family_name)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.font_system
|
||||
.db()
|
||||
.face(id)
|
||||
.is_some_and(|face| face.families.iter().any(|(name, _)| name == family_name))
|
||||
}
|
||||
|
||||
fn default_font_match_key(&self) -> Option<&FontMatchKey> {
|
||||
|
|
@ -304,7 +305,7 @@ impl<'a> FontFallbackIter<'a> {
|
|||
'DEF_FAM: while self.default_i < self.default_families.len() {
|
||||
self.default_i += 1;
|
||||
let is_mono = self.default_families[self.default_i - 1] == &Family::Monospace;
|
||||
let default_font_match_key = self.default_font_match_key().cloned();
|
||||
let default_font_match_key = self.default_font_match_key().copied();
|
||||
let word_chars_count = self.word.chars().count();
|
||||
|
||||
macro_rules! mk_mono_fallback_info {
|
||||
|
|
@ -334,9 +335,8 @@ impl<'a> FontFallbackIter<'a> {
|
|||
(false, Some(m_key)) => {
|
||||
if let Some(font) = self.font_system.get_font(m_key.id, self.ideal_weight) {
|
||||
return Some(font);
|
||||
} else {
|
||||
break 'DEF_FAM;
|
||||
}
|
||||
break 'DEF_FAM;
|
||||
}
|
||||
(true, None) => (),
|
||||
(true, Some(m_key)) => {
|
||||
|
|
@ -360,7 +360,7 @@ impl<'a> FontFallbackIter<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mono_ids_for_scripts = if is_mono && !self.scripts.is_empty() {
|
||||
let scripts = self.scripts.iter().filter_map(|script| {
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@ impl Fallback for PlatformFallback {
|
|||
}
|
||||
|
||||
// Fallbacks to use after any script specific fallbacks
|
||||
fn common_fallback() -> &'static [&'static str] {
|
||||
const fn common_fallback() -> &'static [&'static str] {
|
||||
&[]
|
||||
}
|
||||
|
||||
// Fallbacks to never use
|
||||
fn forbidden_fallback() -> &'static [&'static str] {
|
||||
const fn forbidden_fallback() -> &'static [&'static str] {
|
||||
&[]
|
||||
}
|
||||
|
||||
// Fallbacks to use per script
|
||||
fn script_fallback(_script: Script, _locale: &str) -> &'static [&'static str] {
|
||||
const fn script_fallback(_script: Script, _locale: &str) -> &'static [&'static str] {
|
||||
&[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl Fallback for PlatformFallback {
|
|||
}
|
||||
|
||||
// Fallbacks to use after any script specific fallbacks
|
||||
fn common_fallback() -> &'static [&'static str] {
|
||||
const fn common_fallback() -> &'static [&'static str] {
|
||||
//TODO: abstract style (sans/serif/monospaced)
|
||||
&[
|
||||
/* Sans-serif fallbacks */
|
||||
|
|
@ -49,7 +49,7 @@ fn common_fallback() -> &'static [&'static str] {
|
|||
}
|
||||
|
||||
// Fallbacks to never use
|
||||
fn forbidden_fallback() -> &'static [&'static str] {
|
||||
const fn forbidden_fallback() -> &'static [&'static str] {
|
||||
&[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use alloc::vec::Vec;
|
|||
use rustybuzz::Face as RustybuzzFace;
|
||||
use self_cell::self_cell;
|
||||
|
||||
pub(crate) mod fallback;
|
||||
pub mod fallback;
|
||||
pub use fallback::{Fallback, PlatformFallback};
|
||||
|
||||
pub use self::system::*;
|
||||
|
|
@ -58,7 +58,7 @@ impl fmt::Debug for Font {
|
|||
}
|
||||
|
||||
impl Font {
|
||||
pub fn id(&self) -> fontdb::ID {
|
||||
pub const fn id(&self) -> fontdb::ID {
|
||||
self.id
|
||||
}
|
||||
|
||||
|
|
@ -119,9 +119,9 @@ impl Font {
|
|||
let monospace_em_width = info
|
||||
.monospaced
|
||||
.then(|| {
|
||||
let hor_advance = face.glyph_hor_advance(face.glyph_index(' ')?)? as f32;
|
||||
let upem = face.units_per_em() as f32;
|
||||
Some(hor_advance / upem)
|
||||
let hor_advance = face.glyph_hor_advance(face.glyph_index(' ')?)?;
|
||||
let upem = face.units_per_em();
|
||||
Some(f32::from(hor_advance) / f32::from(upem))
|
||||
})
|
||||
.flatten();
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ impl Font {
|
|||
.cmap?
|
||||
.subtables
|
||||
.into_iter()
|
||||
.filter(|subtable| subtable.is_unicode())
|
||||
.filter(ttf_parser::cmap::Subtable::is_unicode)
|
||||
.for_each(|subtable| {
|
||||
unicode_codepoints.reserve(1024);
|
||||
subtable.codepoints(|code_point| {
|
||||
|
|
@ -194,7 +194,7 @@ impl Font {
|
|||
.into_iter()
|
||||
.find(|axis| axis.tag == ttf_parser::Tag::from_bytes(b"wght"))
|
||||
{
|
||||
let wght = (weight.0 as f32).clamp(axis.min_value, axis.max_value);
|
||||
let wght = f32::from(weight.0).clamp(axis.min_value, axis.max_value);
|
||||
let _ = face.set_variation(ttf_parser::Tag::from_bytes(b"wght"), wght);
|
||||
}
|
||||
face
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ impl fmt::Debug for FontSystem {
|
|||
f.debug_struct("FontSystem")
|
||||
.field("locale", &self.locale)
|
||||
.field("db", &self.db)
|
||||
.finish()
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ impl FontSystem {
|
|||
HashMap::default();
|
||||
|
||||
if cfg!(feature = "monospace_fallback") {
|
||||
monospace_font_ids.iter().for_each(|&id| {
|
||||
for &id in &monospace_font_ids {
|
||||
db.with_face_data(id, |font_data, face_index| {
|
||||
let _ = ttf_parser::Face::parse(font_data, face_index).map(|face| {
|
||||
face.tables()
|
||||
|
|
@ -196,7 +196,7 @@ impl FontSystem {
|
|||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let per_script_monospace_font_ids = per_script_monospace_font_ids
|
||||
|
|
@ -211,9 +211,9 @@ impl FontSystem {
|
|||
db,
|
||||
monospace_font_ids,
|
||||
per_script_monospace_font_ids,
|
||||
font_cache: Default::default(),
|
||||
font_matches_cache: Default::default(),
|
||||
font_codepoint_support_info_cache: Default::default(),
|
||||
font_cache: HashMap::default(),
|
||||
font_matches_cache: HashMap::default(),
|
||||
font_codepoint_support_info_cache: HashMap::default(),
|
||||
monospace_fallbacks_buffer: BTreeSet::default(),
|
||||
#[cfg(feature = "shape-run-cache")]
|
||||
shape_run_cache: crate::ShapeRunCache::default(),
|
||||
|
|
@ -234,7 +234,7 @@ impl FontSystem {
|
|||
}
|
||||
|
||||
/// Get the database.
|
||||
pub fn db(&self) -> &fontdb::Database {
|
||||
pub const fn db(&self) -> &fontdb::Database {
|
||||
&self.db
|
||||
}
|
||||
|
||||
|
|
@ -258,15 +258,14 @@ impl FontSystem {
|
|||
unsafe {
|
||||
self.db.make_shared_face_data(id);
|
||||
}
|
||||
match Font::new(&self.db, id, weight) {
|
||||
Some(font) => Some(Arc::new(font)),
|
||||
None => {
|
||||
log::warn!(
|
||||
"failed to load font '{}'",
|
||||
self.db.face(id)?.post_script_name
|
||||
);
|
||||
None
|
||||
}
|
||||
if let Some(font) = Font::new(&self.db, id, weight) {
|
||||
Some(Arc::new(font))
|
||||
} else {
|
||||
log::warn!(
|
||||
"failed to load font '{}'",
|
||||
self.db.face(id)?.post_script_name
|
||||
);
|
||||
None
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ impl SubpixelBin {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_float(&self) -> f32 {
|
||||
pub const fn as_float(&self) -> f32 {
|
||||
match self {
|
||||
Self::Zero => 0.0,
|
||||
Self::One => 0.25,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
use core::fmt::Display;
|
||||
|
||||
use crate::{math, CacheKey, CacheKeyFlags, Color};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{math, CacheKey, CacheKeyFlags, Color};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core_maths::CoreFloat;
|
||||
|
||||
/// A laid out glyph
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -78,8 +80,8 @@ impl LayoutGlyph {
|
|||
self.glyph_id,
|
||||
self.font_size * scale,
|
||||
(
|
||||
(self.x + x_offset) * scale + offset.0,
|
||||
math::truncf((self.y - y_offset) * scale + offset.1), // Hinting in Y axis
|
||||
(self.x + x_offset).mul_add(scale, offset.0),
|
||||
math::truncf((self.y - y_offset).mul_add(scale, offset.1)), // Hinting in Y axis
|
||||
),
|
||||
self.font_weight,
|
||||
self.cache_key_flags,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub enum LineEnding {
|
|||
|
||||
impl LineEnding {
|
||||
/// Get the line ending as a str
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
pub const fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Lf => "\n",
|
||||
Self::CrLf => "\r\n",
|
||||
|
|
@ -39,7 +39,7 @@ pub struct LineIter<'a> {
|
|||
|
||||
impl<'a> LineIter<'a> {
|
||||
/// Create an iterator of lines in a string slice
|
||||
pub fn new(string: &'a str) -> Self {
|
||||
pub const fn new(string: &'a str) -> Self {
|
||||
Self {
|
||||
string,
|
||||
start: 0,
|
||||
|
|
@ -61,9 +61,9 @@ impl Iterator for LineIter<'_> {
|
|||
LineEnding::CrLf
|
||||
} else if after.starts_with("\n\r") {
|
||||
LineEnding::LfCr
|
||||
} else if after.starts_with("\n") {
|
||||
} else if after.starts_with('\n') {
|
||||
LineEnding::Lf
|
||||
} else if after.starts_with("\r") {
|
||||
} else if after.starts_with('\r') {
|
||||
LineEnding::Cr
|
||||
} else {
|
||||
//TODO: this should not be possible
|
||||
|
|
|
|||
137
src/shape.rs
137
src/shape.rs
|
|
@ -2,20 +2,23 @@
|
|||
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::{max, min};
|
||||
use core::fmt;
|
||||
use core::mem;
|
||||
use core::ops::Range;
|
||||
use unicode_script::{Script, UnicodeScript};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use crate::fallback::FontFallbackIter;
|
||||
use crate::{
|
||||
math, Align, AttrsList, CacheKeyFlags, Color, Font, FontSystem, LayoutGlyph, LayoutLine,
|
||||
Metrics, Wrap,
|
||||
};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use core::cmp::{max, min};
|
||||
use core::fmt;
|
||||
use core::mem;
|
||||
use core::ops::Range;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core_maths::CoreFloat;
|
||||
use unicode_script::{Script, UnicodeScript};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
/// The shaping strategy of some text.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -117,8 +120,8 @@ fn shape_fallback(
|
|||
let run = &line[start_run..end_run];
|
||||
|
||||
let font_scale = font.rustybuzz().units_per_em() as f32;
|
||||
let ascent = font.rustybuzz().ascender() as f32 / font_scale;
|
||||
let descent = -font.rustybuzz().descender() as f32 / font_scale;
|
||||
let ascent = f32::from(font.rustybuzz().ascender()) / font_scale;
|
||||
let descent = -f32::from(font.rustybuzz().descender()) / font_scale;
|
||||
|
||||
let mut buffer = scratch.rustybuzz_buffer.take().unwrap_or_default();
|
||||
buffer.set_direction(if span_rtl {
|
||||
|
|
@ -197,7 +200,7 @@ fn shape_fallback(
|
|||
color_opt: attrs.color_opt,
|
||||
metadata: attrs.metadata,
|
||||
cache_key_flags: attrs.cache_key_flags,
|
||||
metrics_opt: attrs.metrics_opt.map(|x| x.into()),
|
||||
metrics_opt: attrs.metrics_opt.map(Into::into),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -286,9 +289,8 @@ fn shape_run(
|
|||
|
||||
//TODO: improve performance!
|
||||
while !missing.is_empty() {
|
||||
let font = match font_iter.next() {
|
||||
Some(some) => some,
|
||||
None => break,
|
||||
let Some(font) = font_iter.next() else {
|
||||
break;
|
||||
};
|
||||
|
||||
log::trace!(
|
||||
|
|
@ -335,9 +337,8 @@ fn shape_run(
|
|||
while i < glyphs.len() {
|
||||
if glyphs[i].start >= start && glyphs[i].end <= end {
|
||||
break;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Remove prior glyphs
|
||||
|
|
@ -495,7 +496,7 @@ fn shape_skip(
|
|||
color_opt: attrs.color_opt,
|
||||
metadata: attrs.metadata,
|
||||
cache_key_flags: attrs.cache_key_flags,
|
||||
metrics_opt: attrs.metrics_opt.map(|x| x.into()),
|
||||
metrics_opt: attrs.metrics_opt.map(Into::into),
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
|
@ -523,7 +524,7 @@ pub struct ShapeGlyph {
|
|||
}
|
||||
|
||||
impl ShapeGlyph {
|
||||
fn layout(
|
||||
const fn layout(
|
||||
&self,
|
||||
font_size: f32,
|
||||
line_height_opt: Option<f32>,
|
||||
|
|
@ -633,7 +634,7 @@ impl ShapeWord {
|
|||
word.is_ascii() && !word.chars().any(|c| c.is_ascii_control() && c != '\t');
|
||||
|
||||
if is_simple_ascii && !word.is_empty() {
|
||||
let attrs = attrs_list.defaults();
|
||||
let _attrs = attrs_list.defaults();
|
||||
shaping.run(
|
||||
&mut glyphs,
|
||||
font_system,
|
||||
|
|
@ -685,7 +686,7 @@ impl ShapeWord {
|
|||
/// Get the width of the [`ShapeWord`] in pixels, using the [`ShapeGlyph::width`] function.
|
||||
pub fn width(&self, font_size: f32) -> f32 {
|
||||
let mut width = 0.0;
|
||||
for glyph in self.glyphs.iter() {
|
||||
for glyph in &self.glyphs {
|
||||
width += glyph.width(font_size);
|
||||
}
|
||||
width
|
||||
|
|
@ -920,7 +921,7 @@ impl ShapeLine {
|
|||
|
||||
log::trace!("Line {}: '{}'", if rtl { "RTL" } else { "LTR" }, line);
|
||||
|
||||
for para_info in bidi.paragraphs.iter() {
|
||||
for para_info in &bidi.paragraphs {
|
||||
let line_rtl = para_info.level.is_rtl();
|
||||
assert_eq!(line_rtl, rtl);
|
||||
|
||||
|
|
@ -971,12 +972,12 @@ impl ShapeLine {
|
|||
|
||||
// Adjust for tabs
|
||||
let mut x = 0.0;
|
||||
for span in spans.iter_mut() {
|
||||
for word in span.words.iter_mut() {
|
||||
for glyph in word.glyphs.iter_mut() {
|
||||
for span in &mut spans {
|
||||
for word in &mut span.words {
|
||||
for glyph in &mut word.glyphs {
|
||||
if line.get(glyph.start..glyph.end) == Some("\t") {
|
||||
// Tabs are shaped as spaces, so they will always have the x_advance of a space.
|
||||
let tab_x_advance = (tab_width as f32) * glyph.x_advance;
|
||||
let tab_x_advance = f32::from(tab_width) * glyph.x_advance;
|
||||
let tab_stop = (math::floorf(x / tab_x_advance) + 1.0) * tab_x_advance;
|
||||
glyph.x_advance = tab_stop - x;
|
||||
}
|
||||
|
|
@ -987,7 +988,7 @@ impl ShapeLine {
|
|||
|
||||
self.rtl = rtl;
|
||||
self.spans = spans;
|
||||
self.metrics_opt = attrs_list.defaults().metrics_opt.map(|x| x.into());
|
||||
self.metrics_opt = attrs_list.defaults().metrics_opt.map(Into::into);
|
||||
|
||||
// Return the buffer for later reuse.
|
||||
font_system.shape_buffer.spans = cached_spans;
|
||||
|
|
@ -995,7 +996,7 @@ impl ShapeLine {
|
|||
|
||||
// A modified version of first part of unicode_bidi::bidi_info::visual_run
|
||||
fn adjust_levels(para: &unicode_bidi::Paragraph) -> Vec<unicode_bidi::Level> {
|
||||
use unicode_bidi::BidiClass::*;
|
||||
use unicode_bidi::BidiClass::{B, BN, FSI, LRE, LRI, LRO, PDF, PDI, RLE, RLI, RLO, S, WS};
|
||||
let text = para.info.text;
|
||||
let levels = ¶.info.levels;
|
||||
let original_classes = ¶.info.original_classes;
|
||||
|
|
@ -1141,6 +1142,23 @@ impl ShapeLine {
|
|||
layout_lines: &mut Vec<LayoutLine>,
|
||||
match_mono_width: Option<f32>,
|
||||
) {
|
||||
fn add_to_visual_line(
|
||||
vl: &mut VisualLine,
|
||||
span_index: usize,
|
||||
start: (usize, usize),
|
||||
end: (usize, usize),
|
||||
width: f32,
|
||||
number_of_blanks: u32,
|
||||
) {
|
||||
if end == start {
|
||||
return;
|
||||
}
|
||||
|
||||
vl.ranges.push((span_index, start, end));
|
||||
vl.w += width;
|
||||
vl.spaces += number_of_blanks;
|
||||
}
|
||||
|
||||
// For each visual line a list of (span index, and range of words in that span)
|
||||
// Note that a BiDi visual line could have multiple spans or parts of them
|
||||
// let mut vl_range_of_spans = Vec::with_capacity(1);
|
||||
|
|
@ -1160,23 +1178,6 @@ impl ShapeLine {
|
|||
v.glyphs
|
||||
}));
|
||||
|
||||
fn add_to_visual_line(
|
||||
vl: &mut VisualLine,
|
||||
span_index: usize,
|
||||
start: (usize, usize),
|
||||
end: (usize, usize),
|
||||
width: f32,
|
||||
number_of_blanks: u32,
|
||||
) {
|
||||
if end == start {
|
||||
return;
|
||||
}
|
||||
|
||||
vl.ranges.push((span_index, start, end));
|
||||
vl.w += width;
|
||||
vl.spaces += number_of_blanks;
|
||||
}
|
||||
|
||||
// This would keep the maximum number of spans that would fit on a visual line
|
||||
// If one span is too large, this variable will hold the range of words inside that span
|
||||
// that fits on a line.
|
||||
|
|
@ -1187,7 +1188,7 @@ impl ShapeLine {
|
|||
for (span_index, span) in self.spans.iter().enumerate() {
|
||||
let mut word_range_width = 0.;
|
||||
let mut number_of_blanks: u32 = 0;
|
||||
for word in span.words.iter() {
|
||||
for word in &span.words {
|
||||
let word_width = word.width(font_size);
|
||||
word_range_width += word_width;
|
||||
if word.blank {
|
||||
|
|
@ -1232,7 +1233,6 @@ impl ShapeLine {
|
|||
width_before_last_blank = word_range_width;
|
||||
}
|
||||
word_range_width += word_width;
|
||||
continue;
|
||||
} else if wrap == Wrap::Glyph
|
||||
// Make sure that the word is able to fit on it's own line, if not, fall back to Glyph wrapping.
|
||||
|| (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
|
||||
|
|
@ -1266,7 +1266,6 @@ impl ShapeLine {
|
|||
<= width_opt.unwrap_or(f32::INFINITY)
|
||||
{
|
||||
word_range_width += glyph_width;
|
||||
continue;
|
||||
} else {
|
||||
add_to_visual_line(
|
||||
&mut current_visual_line,
|
||||
|
|
@ -1358,7 +1357,6 @@ impl ShapeLine {
|
|||
width_before_last_blank = word_range_width;
|
||||
}
|
||||
word_range_width += word_width;
|
||||
continue;
|
||||
} else if wrap == Wrap::Glyph
|
||||
// Make sure that the word is able to fit on it's own line, if not, fall back to Glyph wrapping.
|
||||
|| (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
|
||||
|
|
@ -1392,7 +1390,6 @@ impl ShapeLine {
|
|||
<= width_opt.unwrap_or(f32::INFINITY)
|
||||
{
|
||||
word_range_width += glyph_width;
|
||||
continue;
|
||||
} else {
|
||||
add_to_visual_line(
|
||||
&mut current_visual_line,
|
||||
|
|
@ -1467,26 +1464,26 @@ impl ShapeLine {
|
|||
}
|
||||
}
|
||||
|
||||
if !current_visual_line.ranges.is_empty() {
|
||||
visual_lines.push(current_visual_line);
|
||||
} else {
|
||||
if current_visual_line.ranges.is_empty() {
|
||||
current_visual_line.clear();
|
||||
cached_visual_lines.push(current_visual_line);
|
||||
} else {
|
||||
visual_lines.push(current_visual_line);
|
||||
}
|
||||
|
||||
// Create the LayoutLines using the ranges inside visual lines
|
||||
let align = align.unwrap_or(if self.rtl { Align::Right } else { Align::Left });
|
||||
|
||||
let line_width = match width_opt {
|
||||
Some(width) => width,
|
||||
None => {
|
||||
let line_width = width_opt.map_or_else(
|
||||
|| {
|
||||
let mut width: f32 = 0.0;
|
||||
for visual_line in visual_lines.iter() {
|
||||
for visual_line in &visual_lines {
|
||||
width = width.max(visual_line.w);
|
||||
}
|
||||
width
|
||||
}
|
||||
};
|
||||
},
|
||||
|width| width,
|
||||
);
|
||||
|
||||
let start_x = if self.rtl { line_width } else { 0.0 };
|
||||
|
||||
|
|
@ -1546,7 +1543,7 @@ impl ShapeLine {
|
|||
|
||||
let mut process_range = |range: Range<usize>| {
|
||||
for &(span_index, (starting_word, starting_glyph), (ending_word, ending_glyph)) in
|
||||
visual_line.ranges[range.clone()].iter()
|
||||
&visual_line.ranges[range]
|
||||
{
|
||||
let span = &self.spans[span_index];
|
||||
// If ending_glyph is not 0 we need to include glyphs from the ending_word
|
||||
|
|
@ -1585,12 +1582,14 @@ impl ShapeLine {
|
|||
_ => font_size,
|
||||
};
|
||||
|
||||
let x_advance = glyph_font_size * glyph.x_advance
|
||||
+ if word.blank {
|
||||
let x_advance = glyph_font_size.mul_add(
|
||||
glyph.x_advance,
|
||||
if word.blank {
|
||||
justification_expansion
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
},
|
||||
);
|
||||
if self.rtl {
|
||||
x -= x_advance;
|
||||
}
|
||||
|
|
@ -1626,12 +1625,12 @@ impl ShapeLine {
|
|||
}
|
||||
|
||||
let mut line_height_opt: Option<f32> = None;
|
||||
for glyph in glyphs.iter() {
|
||||
for glyph in &glyphs {
|
||||
if let Some(glyph_line_height) = glyph.line_height_opt {
|
||||
line_height_opt = match line_height_opt {
|
||||
Some(line_height) => Some(line_height.max(glyph_line_height)),
|
||||
None => Some(glyph_line_height),
|
||||
};
|
||||
line_height_opt = line_height_opt
|
||||
.map_or(Some(glyph_line_height), |line_height| {
|
||||
Some(line_height.max(glyph_line_height))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1657,7 +1656,7 @@ impl ShapeLine {
|
|||
max_ascent: 0.0,
|
||||
max_descent: 0.0,
|
||||
line_height_opt: self.metrics_opt.map(|x| x.line_height),
|
||||
glyphs: Default::default(),
|
||||
glyphs: Vec::default(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
22
src/swash.rs
22
src/swash.rs
|
|
@ -17,12 +17,9 @@ fn swash_image(
|
|||
context: &mut ScaleContext,
|
||||
cache_key: CacheKey,
|
||||
) -> Option<SwashImage> {
|
||||
let font = match font_system.get_font(cache_key.font_id, cache_key.font_weight) {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
log::warn!("did not find font {:?}", cache_key.font_id);
|
||||
return None;
|
||||
}
|
||||
let Some(font) = font_system.get_font(cache_key.font_id, cache_key.font_weight) else {
|
||||
log::warn!("did not find font {:?}", cache_key.font_id);
|
||||
return None;
|
||||
};
|
||||
|
||||
let variable_width = font
|
||||
|
|
@ -38,7 +35,7 @@ fn swash_image(
|
|||
if let Some(variation) = variable_width {
|
||||
scaler = scaler.variations(std::iter::once(swash::Setting {
|
||||
tag: swash::Tag::from_be_bytes(*b"wght"),
|
||||
value: (cache_key.font_weight.0 as f32)
|
||||
value: f32::from(cache_key.font_weight.0)
|
||||
.clamp(variation.min_value(), variation.max_value()),
|
||||
}));
|
||||
}
|
||||
|
|
@ -87,12 +84,9 @@ fn swash_outline_commands(
|
|||
) -> Option<Box<[swash::zeno::Command]>> {
|
||||
use swash::zeno::PathData as _;
|
||||
|
||||
let font = match font_system.get_font(cache_key.font_id, cache_key.font_weight) {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
log::warn!("did not find font {:?}", cache_key.font_id);
|
||||
return None;
|
||||
}
|
||||
let Some(font) = font_system.get_font(cache_key.font_id, cache_key.font_weight) else {
|
||||
log::warn!("did not find font {:?}", cache_key.font_id);
|
||||
return None;
|
||||
};
|
||||
|
||||
// Build the scaler
|
||||
|
|
@ -206,7 +200,7 @@ impl SwashCache {
|
|||
f(
|
||||
x + off_x,
|
||||
y + off_y,
|
||||
Color(((image.data[i] as u32) << 24) | base.0 & 0xFF_FF_FF),
|
||||
Color((u32::from(image.data[i]) << 24) | base.0 & 0xFF_FF_FF),
|
||||
);
|
||||
i += 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue