From ad111a1df10d5da503620f4b841de5d41ebd4e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 19 Apr 2023 00:24:43 +0200 Subject: [PATCH 1/7] Add `skip_shaping` flag to avoid expensive shaping when not needed --- src/buffer.rs | 29 +++++++++---- src/buffer_line.rs | 13 ++++-- src/edit/editor.rs | 3 ++ src/lib.rs | 2 +- src/shape.rs | 106 ++++++++++++++++++++++++++++++++++++++------- 5 files changed, 125 insertions(+), 28 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index 123ce384b9..fd3df69d7d 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -331,7 +331,7 @@ impl Buffer { redraw: false, wrap: Wrap::Word, }; - buffer.set_text(font_system, "", Attrs::new()); + buffer.set_text(font_system, "", Attrs::new(), true); buffer } @@ -562,16 +562,28 @@ impl Buffer { } /// Set text of buffer, using provided attributes for each line by default - pub fn set_text(&mut self, font_system: &mut FontSystem, text: &str, attrs: Attrs) { + pub fn set_text( + &mut self, + font_system: &mut FontSystem, + text: &str, + attrs: Attrs, + skip_shaping: bool, + ) { self.lines.clear(); for line in text.lines() { - self.lines - .push(BufferLine::new(line.to_string(), AttrsList::new(attrs))); + self.lines.push(BufferLine::new( + line.to_string(), + AttrsList::new(attrs), + skip_shaping, + )); } // Make sure there is always one line if self.lines.is_empty() { - self.lines - .push(BufferLine::new(String::new(), AttrsList::new(attrs))); + self.lines.push(BufferLine::new( + String::new(), + AttrsList::new(attrs), + skip_shaping, + )); } self.scroll = 0; @@ -769,8 +781,9 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> { } /// Set text of buffer, using provided attributes for each line by default - pub fn set_text(&mut self, text: &str, attrs: Attrs) { - self.inner.set_text(self.font_system, text, attrs); + pub fn set_text(&mut self, text: &str, attrs: Attrs, skip_shaping: bool) { + self.inner + .set_text(self.font_system, text, attrs, skip_shaping); } /// Draw the buffer diff --git a/src/buffer_line.rs b/src/buffer_line.rs index fb808f0551..2bedd8be6c 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -12,13 +12,14 @@ pub struct BufferLine { align: Option, shape_opt: Option, layout_opt: Option>, + skip_shaping: bool, } impl BufferLine { /// Create a new line with the given text and attributes list /// Cached shaping and layout can be done using the [`Self::shape`] and /// [`Self::layout`] functions - pub fn new>(text: T, attrs_list: AttrsList) -> Self { + pub fn new>(text: T, attrs_list: AttrsList, skip_shaping: bool) -> Self { Self { text: text.into(), attrs_list, @@ -26,6 +27,7 @@ impl BufferLine { align: None, shape_opt: None, layout_opt: None, + skip_shaping, } } @@ -142,7 +144,7 @@ impl BufferLine { let attrs_list = self.attrs_list.split_off(index); self.reset(); - let mut new = Self::new(text, attrs_list); + let mut new = Self::new(text, attrs_list, self.skip_shaping); new.wrap = self.wrap; new } @@ -167,7 +169,12 @@ impl BufferLine { /// Shape line, will cache results pub fn shape(&mut self, font_system: &mut FontSystem) -> &ShapeLine { if self.shape_opt.is_none() { - self.shape_opt = Some(ShapeLine::new(font_system, &self.text, &self.attrs_list)); + self.shape_opt = Some(ShapeLine::new( + font_system, + &self.text, + &self.attrs_list, + self.skip_shaping, + )); self.layout_opt = None; } self.shape_opt.as_ref().expect("shape not found") diff --git a/src/edit/editor.rs b/src/edit/editor.rs index 1b82018d52..2a1d8a6384 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -245,6 +245,7 @@ impl Edit for Editor { .strip_suffix(char::is_control) .unwrap_or(data_line), these_attrs, + false, )); } else { panic!("str::lines() did not yield any elements"); @@ -256,6 +257,7 @@ impl Edit for Editor { .strip_suffix(char::is_control) .unwrap_or(data_line), final_attrs.split_off(remaining_split_len), + false, ); tmp.append(after); self.buffer.lines.insert(insert_line, tmp); @@ -270,6 +272,7 @@ impl Edit for Editor { .strip_suffix(char::is_control) .unwrap_or(data_line), final_attrs.split_off(remaining_split_len), + false, ); self.buffer.lines.insert(insert_line, tmp); self.cursor.line += 1; diff --git a/src/lib.rs b/src/lib.rs index 7c98dcb381..fd12af80df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ //! let attrs = Attrs::new(); //! //! // Add some text! -//! buffer.set_text("Hello, Rust! 🦀\n", attrs); +//! buffer.set_text("Hello, Rust! 🦀\n", attrs, false); //! //! // Perform shaping as desired //! buffer.shape_until_scroll(); diff --git a/src/shape.rs b/src/shape.rs index d3ba9bdb5e..fcb259bbc6 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -213,6 +213,49 @@ fn shape_run( glyphs } +fn shape_skip( + font_system: &mut FontSystem, + line: &str, + attrs_list: &AttrsList, + start_run: usize, + end_run: usize, +) -> Vec { + let attrs = attrs_list.get_span(start_run); + let fonts = font_system.get_font_matches(attrs); + + let default_families = [&attrs.family]; + let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, vec![]); + + let font = font_iter.next().expect("no default font found"); + let font_id = font.id(); + let font = font.as_swash(); + + let charmap = font.charmap(); + let glyph_metrics = font.glyph_metrics(&[]).scale(1.0); + + line[start_run..end_run] + .chars() + .enumerate() + .map(|(i, codepoint)| { + let glyph_id = charmap.map(codepoint); + let x_advance = glyph_metrics.advance_width(glyph_id); + + ShapeGlyph { + start: i, + end: i + 1, + x_advance, + y_advance: 0.0, + x_offset: 0.0, + y_offset: 0.0, + font_id, + glyph_id, + color_opt: attrs.color_opt, + metadata: attrs.metadata, + } + }) + .collect() +} + /// A shaped glyph pub struct ShapeGlyph { pub start: usize, @@ -278,6 +321,7 @@ impl ShapeWord { word_range: Range, level: unicode_bidi::Level, blank: bool, + skip_shaping: bool, ) -> Self { let word = &line[word_range.clone()]; @@ -297,30 +341,50 @@ impl ShapeWord { let attrs_egc = attrs_list.get_span(start_egc); if !attrs.compatible(&attrs_egc) { //TODO: more efficient + if skip_shaping { + glyphs.append(&mut shape_skip( + font_system, + line, + attrs_list, + start_run, + start_egc, + )); + } else { + glyphs.append(&mut shape_run( + font_system, + line, + attrs_list, + start_run, + start_egc, + span_rtl, + )); + }; + + start_run = start_egc; + attrs = attrs_egc; + } + } + if start_run < word_range.end { + //TODO: more efficient + if skip_shaping { + glyphs.append(&mut shape_skip( + font_system, + line, + attrs_list, + start_run, + word_range.end, + )); + } else { glyphs.append(&mut shape_run( font_system, line, attrs_list, start_run, - start_egc, + word_range.end, span_rtl, )); - - start_run = start_egc; - attrs = attrs_egc; } } - if start_run < word_range.end { - //TODO: more efficient - glyphs.append(&mut shape_run( - font_system, - line, - attrs_list, - start_run, - word_range.end, - span_rtl, - )); - } let mut x_advance = 0.0; let mut y_advance = 0.0; @@ -352,6 +416,7 @@ impl ShapeSpan { span_range: Range, line_rtl: bool, level: unicode_bidi::Level, + skip_shaping: bool, ) -> Self { let span = &line[span_range.start..span_range.end]; @@ -382,6 +447,7 @@ impl ShapeSpan { (span_range.start + start_word)..(span_range.start + start_lb), level, false, + skip_shaping, )); } if start_lb < end_lb { @@ -395,6 +461,7 @@ impl ShapeSpan { ..(span_range.start + start_lb + i + c.len_utf8()), level, true, + skip_shaping, )); } } @@ -437,7 +504,12 @@ impl ShapeLine { /// # Panics /// /// Will panic if `line` contains more than one paragraph. - pub fn new(font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList) -> Self { + pub fn new( + font_system: &mut FontSystem, + line: &str, + attrs_list: &AttrsList, + skip_shaping: bool, + ) -> Self { let mut spans = Vec::new(); let bidi = unicode_bidi::BidiInfo::new(line, None); @@ -473,6 +545,7 @@ impl ShapeLine { start..i, line_rtl, run_level, + skip_shaping, )); start = i; run_level = new_level; @@ -485,6 +558,7 @@ impl ShapeLine { start..line_range.end, line_rtl, run_level, + skip_shaping, )); line_rtl }; From 0f055c0a137d031d71ed9c8e4cd1bd4d45e0b4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 21 Apr 2023 20:24:44 +0200 Subject: [PATCH 2/7] Replace `skip_shaping` boolean with `Shaping` enum --- src/buffer.rs | 15 ++++---- src/buffer_line.rs | 12 +++--- src/edit/editor.rs | 7 ++-- src/lib.rs | 4 +- src/shape.rs | 91 ++++++++++++++++++++++++---------------------- 5 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index fd3df69d7d..826b8efd7b 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -12,7 +12,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::Color; use crate::{ Attrs, AttrsList, BorrowedWithFontSystem, BufferLine, FontSystem, LayoutGlyph, LayoutLine, - ShapeLine, Wrap, + ShapeLine, Shaping, Wrap, }; /// Current cursor location @@ -331,7 +331,7 @@ impl Buffer { redraw: false, wrap: Wrap::Word, }; - buffer.set_text(font_system, "", Attrs::new(), true); + buffer.set_text(font_system, "", Attrs::new(), Shaping::Basic); buffer } @@ -567,14 +567,14 @@ impl Buffer { font_system: &mut FontSystem, text: &str, attrs: Attrs, - skip_shaping: bool, + shaping: Shaping, ) { self.lines.clear(); for line in text.lines() { self.lines.push(BufferLine::new( line.to_string(), AttrsList::new(attrs), - skip_shaping, + shaping, )); } // Make sure there is always one line @@ -582,7 +582,7 @@ impl Buffer { self.lines.push(BufferLine::new( String::new(), AttrsList::new(attrs), - skip_shaping, + shaping, )); } @@ -781,9 +781,8 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> { } /// Set text of buffer, using provided attributes for each line by default - pub fn set_text(&mut self, text: &str, attrs: Attrs, skip_shaping: bool) { - self.inner - .set_text(self.font_system, text, attrs, skip_shaping); + pub fn set_text(&mut self, text: &str, attrs: Attrs, shaping: Shaping) { + self.inner.set_text(self.font_system, text, attrs, shaping); } /// Draw the buffer diff --git a/src/buffer_line.rs b/src/buffer_line.rs index 2bedd8be6c..4ada0f95f3 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; -use crate::{Align, AttrsList, FontSystem, LayoutLine, ShapeLine, Wrap}; +use crate::{Align, AttrsList, FontSystem, LayoutLine, ShapeLine, Shaping, Wrap}; /// A line (or paragraph) of text that is shaped and laid out pub struct BufferLine { @@ -12,14 +12,14 @@ pub struct BufferLine { align: Option, shape_opt: Option, layout_opt: Option>, - skip_shaping: bool, + shaping: Shaping, } impl BufferLine { /// Create a new line with the given text and attributes list /// Cached shaping and layout can be done using the [`Self::shape`] and /// [`Self::layout`] functions - pub fn new>(text: T, attrs_list: AttrsList, skip_shaping: bool) -> Self { + pub fn new>(text: T, attrs_list: AttrsList, shaping: Shaping) -> Self { Self { text: text.into(), attrs_list, @@ -27,7 +27,7 @@ impl BufferLine { align: None, shape_opt: None, layout_opt: None, - skip_shaping, + shaping, } } @@ -144,7 +144,7 @@ impl BufferLine { let attrs_list = self.attrs_list.split_off(index); self.reset(); - let mut new = Self::new(text, attrs_list, self.skip_shaping); + let mut new = Self::new(text, attrs_list, self.shaping); new.wrap = self.wrap; new } @@ -173,7 +173,7 @@ impl BufferLine { font_system, &self.text, &self.attrs_list, - self.skip_shaping, + self.shaping, )); self.layout_opt = None; } diff --git a/src/edit/editor.rs b/src/edit/editor.rs index 2a1d8a6384..ff2f00b4d3 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -12,6 +12,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::Color; use crate::{ Action, Affinity, AttrsList, Buffer, BufferLine, Cursor, Edit, FontSystem, LayoutCursor, + Shaping, }; /// A wrapper of [`Buffer`] for easy editing @@ -245,7 +246,7 @@ impl Edit for Editor { .strip_suffix(char::is_control) .unwrap_or(data_line), these_attrs, - false, + Shaping::Advanced, )); } else { panic!("str::lines() did not yield any elements"); @@ -257,7 +258,7 @@ impl Edit for Editor { .strip_suffix(char::is_control) .unwrap_or(data_line), final_attrs.split_off(remaining_split_len), - false, + Shaping::Advanced, ); tmp.append(after); self.buffer.lines.insert(insert_line, tmp); @@ -272,7 +273,7 @@ impl Edit for Editor { .strip_suffix(char::is_control) .unwrap_or(data_line), final_attrs.split_off(remaining_split_len), - false, + Shaping::Advanced, ); self.buffer.lines.insert(insert_line, tmp); self.cursor.line += 1; diff --git a/src/lib.rs b/src/lib.rs index fd12af80df..f4b700e11e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! point, you can use the `SwashCache` to rasterize glyphs into either images or pixels. //! //! ``` -//! use cosmic_text::{Attrs, Color, FontSystem, SwashCache, Buffer, Metrics}; +//! use cosmic_text::{Attrs, Color, FontSystem, SwashCache, Buffer, Metrics, Shaping}; //! //! // A FontSystem provides access to detected system fonts, create one per application //! let mut font_system = FontSystem::new(); @@ -36,7 +36,7 @@ //! let attrs = Attrs::new(); //! //! // Add some text! -//! buffer.set_text("Hello, Rust! 🦀\n", attrs, false); +//! buffer.set_text("Hello, Rust! 🦀\n", attrs, Shaping::Advanced); //! //! // Perform shaping as desired //! buffer.shape_until_scroll(); diff --git a/src/shape.rs b/src/shape.rs index fcb259bbc6..7183618015 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -11,6 +11,31 @@ use unicode_segmentation::UnicodeSegmentation; use crate::fallback::FontFallbackIter; use crate::{Align, AttrsList, CacheKey, Color, Font, FontSystem, LayoutGlyph, LayoutLine, Wrap}; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Shaping { + Basic, + Advanced, +} + +impl Shaping { + fn run( + self, + font_system: &mut FontSystem, + line: &str, + attrs_list: &AttrsList, + start_run: usize, + end_run: usize, + span_rtl: bool, + ) -> Vec { + match self { + Self::Basic => shape_skip(font_system, line, attrs_list, start_run, end_run), + Self::Advanced => { + shape_run(font_system, line, attrs_list, start_run, end_run, span_rtl) + } + } + } +} + fn shape_fallback( font: &Font, line: &str, @@ -321,7 +346,7 @@ impl ShapeWord { word_range: Range, level: unicode_bidi::Level, blank: bool, - skip_shaping: bool, + shaping: Shaping, ) -> Self { let word = &line[word_range.clone()]; @@ -341,50 +366,30 @@ impl ShapeWord { let attrs_egc = attrs_list.get_span(start_egc); if !attrs.compatible(&attrs_egc) { //TODO: more efficient - if skip_shaping { - glyphs.append(&mut shape_skip( - font_system, - line, - attrs_list, - start_run, - start_egc, - )); - } else { - glyphs.append(&mut shape_run( - font_system, - line, - attrs_list, - start_run, - start_egc, - span_rtl, - )); - }; - - start_run = start_egc; - attrs = attrs_egc; - } - } - if start_run < word_range.end { - //TODO: more efficient - if skip_shaping { - glyphs.append(&mut shape_skip( - font_system, - line, - attrs_list, - start_run, - word_range.end, - )); - } else { - glyphs.append(&mut shape_run( + glyphs.append(&mut shaping.run( font_system, line, attrs_list, start_run, - word_range.end, + start_egc, span_rtl, )); + + start_run = start_egc; + attrs = attrs_egc; } } + if start_run < word_range.end { + //TODO: more efficient + glyphs.append(&mut shaping.run( + font_system, + line, + attrs_list, + start_run, + word_range.end, + span_rtl, + )); + } let mut x_advance = 0.0; let mut y_advance = 0.0; @@ -416,7 +421,7 @@ impl ShapeSpan { span_range: Range, line_rtl: bool, level: unicode_bidi::Level, - skip_shaping: bool, + shaping: Shaping, ) -> Self { let span = &line[span_range.start..span_range.end]; @@ -447,7 +452,7 @@ impl ShapeSpan { (span_range.start + start_word)..(span_range.start + start_lb), level, false, - skip_shaping, + shaping, )); } if start_lb < end_lb { @@ -461,7 +466,7 @@ impl ShapeSpan { ..(span_range.start + start_lb + i + c.len_utf8()), level, true, - skip_shaping, + shaping, )); } } @@ -508,7 +513,7 @@ impl ShapeLine { font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList, - skip_shaping: bool, + shaping: Shaping, ) -> Self { let mut spans = Vec::new(); @@ -545,7 +550,7 @@ impl ShapeLine { start..i, line_rtl, run_level, - skip_shaping, + shaping, )); start = i; run_level = new_level; @@ -558,7 +563,7 @@ impl ShapeLine { start..line_range.end, line_rtl, run_level, - skip_shaping, + shaping, )); line_rtl }; From 9e559e150d991609e338170e2100d5bceccbe81d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 21 Apr 2023 20:26:08 +0200 Subject: [PATCH 3/7] Write docs for `Shaping` enum --- src/shape.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/shape.rs b/src/shape.rs index 7183618015..c6b7a37dd9 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -11,9 +11,22 @@ use unicode_segmentation::UnicodeSegmentation; use crate::fallback::FontFallbackIter; use crate::{Align, AttrsList, CacheKey, Color, Font, FontSystem, LayoutGlyph, LayoutLine, Wrap}; +/// The shaping strategy of some text. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Shaping { + /// Basic shaping with no font fallback. + /// + /// This shaping strategy is very cheap, but it will not display complex + /// scripts properly nor try to find missing glyphs in your system fonts. + /// + /// You should use this strategy when you have complete control of the text + /// and the font you are displaying in your application. Basic, + /// Advanced text shaping and font fallback. + /// + /// You will need to enable this strategy if the text contains a complex + /// script, the font used needs it, and/or multiple fonts in your system + /// may be needed to display all of the glyphs. Advanced, } From a5c548b12fd50e4edb1b24e3668352c22f64d770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 21 Apr 2023 20:29:56 +0200 Subject: [PATCH 4/7] Fix `syntect` module --- src/edit/syntect.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/edit/syntect.rs b/src/edit/syntect.rs index f454285699..2c57ca5a20 100644 --- a/src/edit/syntect.rs +++ b/src/edit/syntect.rs @@ -9,7 +9,7 @@ use syntect::parsing::{ParseState, ScopeStack, SyntaxReference, SyntaxSet}; use crate::{ Action, AttrsList, BorrowedWithFontSystem, Buffer, Color, Cursor, Edit, Editor, FontSystem, - Style, Weight, Wrap, + Shaping, Style, Weight, Wrap, }; pub struct SyntaxSystem { @@ -75,7 +75,9 @@ impl<'a> SyntaxEditor<'a> { let path = path.as_ref(); let text = fs::read_to_string(path)?; - self.editor.buffer_mut().set_text(font_system, &text, attrs); + self.editor + .buffer_mut() + .set_text(font_system, &text, attrs, Shaping::Advanced); //TODO: re-use text self.syntax = match self.syntax_system.syntax_set.find_syntax_for_file(path) { From 0dce8b75d1485f8db3fb9111a6d8b88865cee1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 21 Apr 2023 20:35:59 +0200 Subject: [PATCH 5/7] Fix `examples` --- examples/rich-text/src/main.rs | 4 ++-- examples/terminal/src/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index f569884e44..b5d1ab4629 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -2,7 +2,7 @@ use cosmic_text::{ Action, Attrs, AttrsList, Buffer, BufferLine, Color, Edit, Editor, Family, FontSystem, Metrics, - Style, SwashCache, Weight, + Shaping, Style, SwashCache, Weight, }; use orbclient::{EventOption, Renderer, Window, WindowFlag}; use std::{ @@ -143,7 +143,7 @@ fn main() { editor .buffer_mut() .lines - .push(BufferLine::new(line_text, attrs_list)); + .push(BufferLine::new(line_text, attrs_list, Shaping::Advanced)); } let mut swash_cache = SwashCache::new(); diff --git a/examples/terminal/src/main.rs b/examples/terminal/src/main.rs index 852207f9ab..d5fbeda7c7 100644 --- a/examples/terminal/src/main.rs +++ b/examples/terminal/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use cosmic_text::{Attrs, Buffer, Color, FontSystem, Metrics, SwashCache}; +use cosmic_text::{Attrs, Buffer, Color, FontSystem, Metrics, Shaping, SwashCache}; use std::cmp::{self, Ordering}; use termion::{color, cursor}; @@ -28,7 +28,7 @@ fn main() { let attrs = Attrs::new(); // Add some text! - buffer.set_text(" Hi, Rust! 🦀", attrs); + buffer.set_text(" Hi, Rust! 🦀", attrs, Shaping::Advanced); // Perform shaping as desired buffer.shape_until_scroll(); From 87d75531b7b3a49b8d57d06a277dd4c6f176b88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 21 Apr 2023 20:47:02 +0200 Subject: [PATCH 6/7] Allow `Shaping::Basic` only if `swash` feature is enabled --- src/buffer.rs | 2 +- src/shape.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/buffer.rs b/src/buffer.rs index 826b8efd7b..e459e723e4 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -331,7 +331,7 @@ impl Buffer { redraw: false, wrap: Wrap::Word, }; - buffer.set_text(font_system, "", Attrs::new(), Shaping::Basic); + buffer.set_text(font_system, "", Attrs::new(), Shaping::Advanced); buffer } diff --git a/src/shape.rs b/src/shape.rs index c6b7a37dd9..37c219d2a0 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -21,6 +21,7 @@ pub enum Shaping { /// /// You should use this strategy when you have complete control of the text /// and the font you are displaying in your application. + #[cfg(feature = "swash")] Basic, /// Advanced text shaping and font fallback. /// @@ -41,6 +42,7 @@ impl Shaping { span_rtl: bool, ) -> Vec { match self { + #[cfg(feature = "swash")] Self::Basic => shape_skip(font_system, line, attrs_list, start_run, end_run), Self::Advanced => { shape_run(font_system, line, attrs_list, start_run, end_run, span_rtl) @@ -251,6 +253,7 @@ fn shape_run( glyphs } +#[cfg(feature = "swash")] fn shape_skip( font_system: &mut FontSystem, line: &str, From b85d6a4f2376f8a8a7dadc0f8bcb89d4db10a1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 21 Apr 2023 20:56:11 +0200 Subject: [PATCH 7/7] Use `Vec::new` instead of `vec!` macro --- src/shape.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shape.rs b/src/shape.rs index 37c219d2a0..9ce585d951 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -265,7 +265,7 @@ fn shape_skip( let fonts = font_system.get_font_matches(attrs); let default_families = [&attrs.family]; - let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, vec![]); + let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, Vec::new()); let font = font_iter.next().expect("no default font found"); let font_id = font.id();