Update cosmic-text and resvg (#2416)

* Update `cosmic-text`, `glyphon`, and `resvg`

* Fix slow font fallback with `Shaping::Basic` in `cosmic-text`

* Update `cosmic-text` and `resvg`

* Update `cosmic-text`

* Fix `SelectAll` action in `editor`

* Fix some panics in `graphics::text::editor`

* Remove empty `if` statement in `tiny_skia::vector`

* Update `cosmic-text`, `glyphon`, and `rustc-hash`
This commit is contained in:
Héctor Ramón 2024-07-17 13:00:00 +02:00 committed by GitHub
parent b518e30610
commit 616689ca54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 187 additions and 222 deletions

View file

@ -138,11 +138,11 @@ async-std = "1.0"
bitflags = "2.0" bitflags = "2.0"
bytemuck = { version = "1.0", features = ["derive"] } bytemuck = { version = "1.0", features = ["derive"] }
bytes = "1.6" bytes = "1.6"
cosmic-text = "0.10" cosmic-text = "0.12"
dark-light = "1.0" dark-light = "1.0"
futures = "0.3" futures = "0.3"
glam = "0.25" glam = "0.25"
glyphon = { git = "https://github.com/hecrj/glyphon.git", rev = "f07e7bab705e69d39a5e6e52c73039a93c4552f8" } glyphon = { git = "https://github.com/hecrj/glyphon.git", rev = "feef9f5630c2adb3528937e55f7bfad2da561a65" }
guillotiere = "0.6" guillotiere = "0.6"
half = "2.2" half = "2.2"
image = "0.24" image = "0.24"
@ -157,8 +157,8 @@ ouroboros = "0.18"
palette = "0.7" palette = "0.7"
qrcode = { version = "0.13", default-features = false } qrcode = { version = "0.13", default-features = false }
raw-window-handle = "0.6" raw-window-handle = "0.6"
resvg = "0.36" resvg = "0.42"
rustc-hash = "1.0" rustc-hash = "2.0"
smol = "1.0" smol = "1.0"
smol_str = "0.2" smol_str = "0.2"
softbuffer = "0.4" softbuffer = "0.4"

View file

@ -43,6 +43,7 @@ impl Text {
let mut buffer = cosmic_text::BufferLine::new( let mut buffer = cosmic_text::BufferLine::new(
&self.content, &self.content,
cosmic_text::LineEnding::default(),
cosmic_text::AttrsList::new(text::to_attributes(self.font)), cosmic_text::AttrsList::new(text::to_attributes(self.font)),
text::to_shaping(self.shaping), text::to_shaping(self.shaping),
); );
@ -50,8 +51,10 @@ impl Text {
let layout = buffer.layout( let layout = buffer.layout(
font_system.raw(), font_system.raw(),
self.size.0, self.size.0,
f32::MAX, None,
cosmic_text::Wrap::None, cosmic_text::Wrap::None,
None,
4,
); );
let translation_x = match self.horizontal_alignment { let translation_x = match self.horizontal_alignment {

View file

@ -48,8 +48,8 @@ impl Cache {
buffer.set_size( buffer.set_size(
font_system, font_system,
key.bounds.width, Some(key.bounds.width),
key.bounds.height.max(key.line_height), Some(key.bounds.height.max(key.line_height)),
); );
buffer.set_text( buffer.set_text(
font_system, font_system,

View file

@ -17,7 +17,7 @@ use std::sync::{self, Arc};
pub struct Editor(Option<Arc<Internal>>); pub struct Editor(Option<Arc<Internal>>);
struct Internal { struct Internal {
editor: cosmic_text::Editor, editor: cosmic_text::Editor<'static>,
font: Font, font: Font,
bounds: Size, bounds: Size,
topmost_line_changed: Option<usize>, topmost_line_changed: Option<usize>,
@ -32,7 +32,7 @@ impl Editor {
/// Returns the buffer of the [`Editor`]. /// Returns the buffer of the [`Editor`].
pub fn buffer(&self) -> &cosmic_text::Buffer { pub fn buffer(&self) -> &cosmic_text::Buffer {
self.internal().editor.buffer() buffer_from_editor(&self.internal().editor)
} }
/// Creates a [`Weak`] reference to the [`Editor`]. /// Creates a [`Weak`] reference to the [`Editor`].
@ -101,16 +101,10 @@ impl editor::Editor for Editor {
let internal = self.internal(); let internal = self.internal();
let cursor = internal.editor.cursor(); let cursor = internal.editor.cursor();
let buffer = internal.editor.buffer(); let buffer = buffer_from_editor(&internal.editor);
match internal.editor.select_opt() {
Some(selection) => {
let (start, end) = if cursor < selection {
(cursor, selection)
} else {
(selection, cursor)
};
match internal.editor.selection_bounds() {
Some((start, end)) => {
let line_height = buffer.metrics().line_height; let line_height = buffer.metrics().line_height;
let selected_lines = end.line - start.line + 1; let selected_lines = end.line - start.line + 1;
@ -142,7 +136,8 @@ impl editor::Editor for Editor {
width, width,
y: (visual_line as i32 + visual_lines_offset) y: (visual_line as i32 + visual_lines_offset)
as f32 as f32
* line_height, * line_height
- buffer.scroll().vertical,
height: line_height, height: line_height,
}) })
} else { } else {
@ -224,7 +219,8 @@ impl editor::Editor for Editor {
Cursor::Caret(Point::new( Cursor::Caret(Point::new(
offset, offset,
(visual_lines_offset + visual_line as i32) as f32 (visual_lines_offset + visual_line as i32) as f32
* line_height, * line_height
- buffer.scroll().vertical,
)) ))
} }
} }
@ -252,16 +248,8 @@ impl editor::Editor for Editor {
match action { match action {
// Motion events // Motion events
Action::Move(motion) => { Action::Move(motion) => {
if let Some(selection) = editor.select_opt() { if let Some((start, end)) = editor.selection_bounds() {
let cursor = editor.cursor(); editor.set_selection(cosmic_text::Selection::None);
let (left, right) = if cursor < selection {
(cursor, selection)
} else {
(selection, cursor)
};
editor.set_select_opt(None);
match motion { match motion {
// These motions are performed as-is even when a selection // These motions are performed as-is even when a selection
@ -272,17 +260,20 @@ impl editor::Editor for Editor {
| Motion::DocumentEnd => { | Motion::DocumentEnd => {
editor.action( editor.action(
font_system.raw(), font_system.raw(),
motion_to_action(motion), cosmic_text::Action::Motion(to_motion(motion)),
); );
} }
// Other motions simply move the cursor to one end of the selection // Other motions simply move the cursor to one end of the selection
_ => editor.set_cursor(match motion.direction() { _ => editor.set_cursor(match motion.direction() {
Direction::Left => left, Direction::Left => start,
Direction::Right => right, Direction::Right => end,
}), }),
} }
} else { } else {
editor.action(font_system.raw(), motion_to_action(motion)); editor.action(
font_system.raw(),
cosmic_text::Action::Motion(to_motion(motion)),
);
} }
} }
@ -290,103 +281,36 @@ impl editor::Editor for Editor {
Action::Select(motion) => { Action::Select(motion) => {
let cursor = editor.cursor(); let cursor = editor.cursor();
if editor.select_opt().is_none() { if editor.selection_bounds().is_none() {
editor.set_select_opt(Some(cursor)); editor
.set_selection(cosmic_text::Selection::Normal(cursor));
} }
editor.action(font_system.raw(), motion_to_action(motion)); editor.action(
font_system.raw(),
cosmic_text::Action::Motion(to_motion(motion)),
);
// Deselect if selection matches cursor position // Deselect if selection matches cursor position
if let Some(selection) = editor.select_opt() { if let Some((start, end)) = editor.selection_bounds() {
let cursor = editor.cursor(); if start.line == end.line && start.index == end.index {
editor.set_selection(cosmic_text::Selection::None);
if cursor.line == selection.line
&& cursor.index == selection.index
{
editor.set_select_opt(None);
} }
} }
} }
Action::SelectWord => { Action::SelectWord => {
use unicode_segmentation::UnicodeSegmentation;
let cursor = editor.cursor(); let cursor = editor.cursor();
if let Some(line) = editor.buffer().lines.get(cursor.line) { editor.set_selection(cosmic_text::Selection::Word(cursor));
let (start, end) =
UnicodeSegmentation::unicode_word_indices(line.text())
// Split words with dots
.flat_map(|(i, word)| {
word.split('.').scan(i, |current, word| {
let start = *current;
*current += word.len() + 1;
Some((start, word))
})
})
// Turn words into ranges
.map(|(i, word)| (i, i + word.len()))
// Find the word at cursor
.find(|&(start, end)| {
start <= cursor.index && cursor.index < end
})
// Cursor is not in a word. Let's select its punctuation cluster.
.unwrap_or_else(|| {
let start = line.text()[..cursor.index]
.char_indices()
.rev()
.take_while(|(_, c)| {
c.is_ascii_punctuation()
})
.map(|(i, _)| i)
.last()
.unwrap_or(cursor.index);
let end = line.text()[cursor.index..]
.char_indices()
.skip_while(|(_, c)| {
c.is_ascii_punctuation()
})
.map(|(i, _)| i + cursor.index)
.next()
.unwrap_or(cursor.index);
(start, end)
});
if start != end {
editor.set_cursor(cosmic_text::Cursor {
index: start,
..cursor
});
editor.set_select_opt(Some(cosmic_text::Cursor {
index: end,
..cursor
}));
}
}
} }
Action::SelectLine => { Action::SelectLine => {
let cursor = editor.cursor(); let cursor = editor.cursor();
if let Some(line_length) = editor editor.set_selection(cosmic_text::Selection::Line(cursor));
.buffer()
.lines
.get(cursor.line)
.map(|line| line.text().len())
{
editor
.set_cursor(cosmic_text::Cursor { index: 0, ..cursor });
editor.set_select_opt(Some(cosmic_text::Cursor {
index: line_length,
..cursor
}));
}
} }
Action::SelectAll => { Action::SelectAll => {
let buffer = editor.buffer(); let buffer = buffer_from_editor(editor);
if buffer.lines.len() > 1 if buffer.lines.len() > 1
|| buffer || buffer
.lines .lines
@ -394,15 +318,20 @@ impl editor::Editor for Editor {
.is_some_and(|line| !line.text().is_empty()) .is_some_and(|line| !line.text().is_empty())
{ {
let cursor = editor.cursor(); let cursor = editor.cursor();
editor.set_select_opt(Some(cosmic_text::Cursor {
line: 0, editor.set_selection(cosmic_text::Selection::Normal(
index: 0, cosmic_text::Cursor {
..cursor line: 0,
})); index: 0,
..cursor
},
));
editor.action( editor.action(
font_system.raw(), font_system.raw(),
motion_to_action(Motion::DocumentEnd), cosmic_text::Action::Motion(
cosmic_text::Motion::BufferEnd,
),
); );
} }
} }
@ -440,10 +369,12 @@ impl editor::Editor for Editor {
} }
let cursor = editor.cursor(); let cursor = editor.cursor();
let selection = editor.select_opt().unwrap_or(cursor); let selection_start = editor
.selection_bounds()
.map(|(start, _)| start)
.unwrap_or(cursor);
internal.topmost_line_changed = internal.topmost_line_changed = Some(selection_start.line);
Some(cursor.min(selection).line);
} }
// Mouse events // Mouse events
@ -466,13 +397,9 @@ impl editor::Editor for Editor {
); );
// Deselect if selection matches cursor position // Deselect if selection matches cursor position
if let Some(selection) = editor.select_opt() { if let Some((start, end)) = editor.selection_bounds() {
let cursor = editor.cursor(); if start.line == end.line && start.index == end.index {
editor.set_selection(cosmic_text::Selection::None);
if cursor.line == selection.line
&& cursor.index == selection.index
{
editor.set_select_opt(None);
} }
} }
} }
@ -494,7 +421,7 @@ impl editor::Editor for Editor {
fn min_bounds(&self) -> Size { fn min_bounds(&self) -> Size {
let internal = self.internal(); let internal = self.internal();
text::measure(internal.editor.buffer()) text::measure(buffer_from_editor(&internal.editor))
} }
fn update( fn update(
@ -517,7 +444,10 @@ impl editor::Editor for Editor {
if font_system.version() != internal.version { if font_system.version() != internal.version {
log::trace!("Updating `FontSystem` of `Editor`..."); log::trace!("Updating `FontSystem` of `Editor`...");
for line in internal.editor.buffer_mut().lines.iter_mut() { for line in buffer_mut_from_editor(&mut internal.editor)
.lines
.iter_mut()
{
line.reset(); line.reset();
} }
@ -528,7 +458,10 @@ impl editor::Editor for Editor {
if new_font != internal.font { if new_font != internal.font {
log::trace!("Updating font of `Editor`..."); log::trace!("Updating font of `Editor`...");
for line in internal.editor.buffer_mut().lines.iter_mut() { for line in buffer_mut_from_editor(&mut internal.editor)
.lines
.iter_mut()
{
let _ = line.set_attrs_list(cosmic_text::AttrsList::new( let _ = line.set_attrs_list(cosmic_text::AttrsList::new(
text::to_attributes(new_font), text::to_attributes(new_font),
)); ));
@ -538,7 +471,7 @@ impl editor::Editor for Editor {
internal.topmost_line_changed = Some(0); internal.topmost_line_changed = Some(0);
} }
let metrics = internal.editor.buffer().metrics(); let metrics = buffer_from_editor(&internal.editor).metrics();
let new_line_height = new_line_height.to_absolute(new_size); let new_line_height = new_line_height.to_absolute(new_size);
if new_size.0 != metrics.font_size if new_size.0 != metrics.font_size
@ -546,7 +479,7 @@ impl editor::Editor for Editor {
{ {
log::trace!("Updating `Metrics` of `Editor`..."); log::trace!("Updating `Metrics` of `Editor`...");
internal.editor.buffer_mut().set_metrics( buffer_mut_from_editor(&mut internal.editor).set_metrics(
font_system.raw(), font_system.raw(),
cosmic_text::Metrics::new(new_size.0, new_line_height.0), cosmic_text::Metrics::new(new_size.0, new_line_height.0),
); );
@ -555,10 +488,10 @@ impl editor::Editor for Editor {
if new_bounds != internal.bounds { if new_bounds != internal.bounds {
log::trace!("Updating size of `Editor`..."); log::trace!("Updating size of `Editor`...");
internal.editor.buffer_mut().set_size( buffer_mut_from_editor(&mut internal.editor).set_size(
font_system.raw(), font_system.raw(),
new_bounds.width, Some(new_bounds.width),
new_bounds.height, Some(new_bounds.height),
); );
internal.bounds = new_bounds; internal.bounds = new_bounds;
@ -573,7 +506,7 @@ impl editor::Editor for Editor {
new_highlighter.change_line(topmost_line_changed); new_highlighter.change_line(topmost_line_changed);
} }
internal.editor.shape_as_needed(font_system.raw()); internal.editor.shape_as_needed(font_system.raw(), false);
self.0 = Some(Arc::new(internal)); self.0 = Some(Arc::new(internal));
} }
@ -585,12 +518,13 @@ impl editor::Editor for Editor {
format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>, format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>,
) { ) {
let internal = self.internal(); let internal = self.internal();
let buffer = internal.editor.buffer(); let buffer = buffer_from_editor(&internal.editor);
let mut window = buffer.scroll() + buffer.visible_lines(); let scroll = buffer.scroll();
let mut window = (internal.bounds.height / buffer.metrics().line_height)
.ceil() as i32;
let last_visible_line = buffer let last_visible_line = buffer.lines[scroll.line..]
.lines
.iter() .iter()
.enumerate() .enumerate()
.find_map(|(i, line)| { .find_map(|(i, line)| {
@ -604,7 +538,7 @@ impl editor::Editor for Editor {
window -= visible_lines; window -= visible_lines;
None None
} else { } else {
Some(i) Some(scroll.line + i)
} }
}) })
.unwrap_or(buffer.lines.len().saturating_sub(1)); .unwrap_or(buffer.lines.len().saturating_sub(1));
@ -626,7 +560,7 @@ impl editor::Editor for Editor {
let attributes = text::to_attributes(font); let attributes = text::to_attributes(font);
for line in &mut internal.editor.buffer_mut().lines for line in &mut buffer_mut_from_editor(&mut internal.editor).lines
[current_line..=last_visible_line] [current_line..=last_visible_line]
{ {
let mut list = cosmic_text::AttrsList::new(attributes); let mut list = cosmic_text::AttrsList::new(attributes);
@ -652,7 +586,7 @@ impl editor::Editor for Editor {
let _ = line.set_attrs_list(list); let _ = line.set_attrs_list(list);
} }
internal.editor.shape_as_needed(font_system.raw()); internal.editor.shape_as_needed(font_system.raw(), false);
self.0 = Some(Arc::new(internal)); self.0 = Some(Arc::new(internal));
} }
@ -668,7 +602,8 @@ impl PartialEq for Internal {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.font == other.font self.font == other.font
&& self.bounds == other.bounds && self.bounds == other.bounds
&& self.editor.buffer().metrics() == other.editor.buffer().metrics() && buffer_from_editor(&self.editor).metrics()
== buffer_from_editor(&other.editor).metrics()
} }
} }
@ -730,7 +665,8 @@ fn highlight_line(
let layout = line let layout = line
.layout_opt() .layout_opt()
.as_ref() .as_ref()
.expect("Line layout should be cached"); .map(Vec::as_slice)
.unwrap_or_default();
layout.iter().map(move |visual_line| { layout.iter().map(move |visual_line| {
let start = visual_line let start = visual_line
@ -773,34 +709,61 @@ fn highlight_line(
} }
fn visual_lines_offset(line: usize, buffer: &cosmic_text::Buffer) -> i32 { fn visual_lines_offset(line: usize, buffer: &cosmic_text::Buffer) -> i32 {
let visual_lines_before_start: usize = buffer let scroll = buffer.scroll();
.lines
let start = scroll.line.min(line);
let end = scroll.line.max(line);
let visual_lines_offset: usize = buffer.lines[start..]
.iter() .iter()
.take(line) .take(end - start)
.map(|line| { .map(|line| {
line.layout_opt() line.layout_opt().as_ref().map(Vec::len).unwrap_or_default()
.as_ref()
.expect("Line layout should be cached")
.len()
}) })
.sum(); .sum();
visual_lines_before_start as i32 - buffer.scroll() visual_lines_offset as i32 * if scroll.line < line { 1 } else { -1 }
} }
fn motion_to_action(motion: Motion) -> cosmic_text::Action { fn to_motion(motion: Motion) -> cosmic_text::Motion {
match motion { match motion {
Motion::Left => cosmic_text::Action::Left, Motion::Left => cosmic_text::Motion::Left,
Motion::Right => cosmic_text::Action::Right, Motion::Right => cosmic_text::Motion::Right,
Motion::Up => cosmic_text::Action::Up, Motion::Up => cosmic_text::Motion::Up,
Motion::Down => cosmic_text::Action::Down, Motion::Down => cosmic_text::Motion::Down,
Motion::WordLeft => cosmic_text::Action::LeftWord, Motion::WordLeft => cosmic_text::Motion::LeftWord,
Motion::WordRight => cosmic_text::Action::RightWord, Motion::WordRight => cosmic_text::Motion::RightWord,
Motion::Home => cosmic_text::Action::Home, Motion::Home => cosmic_text::Motion::Home,
Motion::End => cosmic_text::Action::End, Motion::End => cosmic_text::Motion::End,
Motion::PageUp => cosmic_text::Action::PageUp, Motion::PageUp => cosmic_text::Motion::PageUp,
Motion::PageDown => cosmic_text::Action::PageDown, Motion::PageDown => cosmic_text::Motion::PageDown,
Motion::DocumentStart => cosmic_text::Action::BufferStart, Motion::DocumentStart => cosmic_text::Motion::BufferStart,
Motion::DocumentEnd => cosmic_text::Action::BufferEnd, Motion::DocumentEnd => cosmic_text::Motion::BufferEnd,
}
}
fn buffer_from_editor<'a, 'b>(
editor: &'a impl cosmic_text::Edit<'b>,
) -> &'a cosmic_text::Buffer
where
'b: 'a,
{
match editor.buffer_ref() {
cosmic_text::BufferRef::Owned(buffer) => buffer,
cosmic_text::BufferRef::Borrowed(buffer) => buffer,
cosmic_text::BufferRef::Arc(buffer) => buffer,
}
}
fn buffer_mut_from_editor<'a, 'b>(
editor: &'a mut impl cosmic_text::Edit<'b>,
) -> &'a mut cosmic_text::Buffer
where
'b: 'a,
{
match editor.buffer_ref_mut() {
cosmic_text::BufferRef::Owned(buffer) => buffer,
cosmic_text::BufferRef::Borrowed(buffer) => buffer,
cosmic_text::BufferRef::Arc(_buffer) => unreachable!(),
} }
} }

View file

@ -77,8 +77,8 @@ impl core::text::Paragraph for Paragraph {
buffer.set_size( buffer.set_size(
font_system.raw(), font_system.raw(),
text.bounds.width, Some(text.bounds.width),
text.bounds.height, Some(text.bounds.height),
); );
buffer.set_text( buffer.set_text(
@ -116,8 +116,8 @@ impl core::text::Paragraph for Paragraph {
internal.buffer.set_size( internal.buffer.set_size(
font_system.raw(), font_system.raw(),
new_bounds.width, Some(new_bounds.width),
new_bounds.height, Some(new_bounds.height),
); );
internal.bounds = new_bounds; internal.bounds = new_bounds;

View file

@ -439,9 +439,13 @@ impl Engine {
let transformation = transformation * *local_transformation; let transformation = transformation * *local_transformation;
let (width, height) = buffer.size(); let (width, height) = buffer.size();
let physical_bounds = let physical_bounds = Rectangle::new(
Rectangle::new(raw.position, Size::new(width, height)) raw.position,
* transformation; Size::new(
width.unwrap_or(clip_bounds.width),
height.unwrap_or(clip_bounds.height),
),
) * transformation;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;

View file

@ -169,7 +169,13 @@ impl Pipeline {
font_system.raw(), font_system.raw(),
&mut self.glyph_cache, &mut self.glyph_cache,
buffer, buffer,
Rectangle::new(position, Size::new(width, height)), Rectangle::new(
position,
Size::new(
width.unwrap_or(pixels.width() as f32),
height.unwrap_or(pixels.height() as f32),
),
),
color, color,
alignment::Horizontal::Left, alignment::Horizontal::Left,
alignment::Vertical::Top, alignment::Vertical::Top,

View file

@ -1,8 +1,7 @@
use crate::core::svg::{Data, Handle}; use crate::core::svg::{Data, Handle};
use crate::core::{Color, Rectangle, Size}; use crate::core::{Color, Rectangle, Size};
use crate::graphics::text;
use resvg::usvg::{self, TreeTextToPath}; use resvg::usvg;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use tiny_skia::Transform; use tiny_skia::Transform;
@ -80,35 +79,28 @@ struct RasterKey {
impl Cache { impl Cache {
fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> { fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> {
use usvg::TreeParsing;
let id = handle.id(); let id = handle.id();
if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) { if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) {
let mut svg = match handle.data() { let svg = match handle.data() {
Data::Path(path) => { Data::Path(path) => {
fs::read_to_string(path).ok().and_then(|contents| { fs::read_to_string(path).ok().and_then(|contents| {
usvg::Tree::from_str( usvg::Tree::from_str(
&contents, &contents,
&usvg::Options::default(), &usvg::Options::default(), // TODO: Set usvg::Options::fontdb
) )
.ok() .ok()
}) })
} }
Data::Bytes(bytes) => { Data::Bytes(bytes) => {
usvg::Tree::from_data(bytes, &usvg::Options::default()).ok() usvg::Tree::from_data(
bytes,
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
)
.ok()
} }
}; };
if let Some(svg) = &mut svg {
if svg.has_text_nodes() {
let mut font_system =
text::font_system().write().expect("Write font system");
svg.convert_text(font_system.raw().db_mut());
}
}
let _ = entry.insert(svg); let _ = entry.insert(svg);
} }
@ -118,11 +110,9 @@ impl Cache {
fn viewport_dimensions(&mut self, handle: &Handle) -> Option<Size<u32>> { fn viewport_dimensions(&mut self, handle: &Handle) -> Option<Size<u32>> {
let tree = self.load(handle)?; let tree = self.load(handle)?;
let size = tree.size();
Some(Size::new( Some(Size::new(size.width() as u32, size.height() as u32))
tree.size.width() as u32,
tree.size.height() as u32,
))
} }
fn draw( fn draw(
@ -147,7 +137,7 @@ impl Cache {
let mut image = tiny_skia::Pixmap::new(size.width, size.height)?; let mut image = tiny_skia::Pixmap::new(size.width, size.height)?;
let tree_size = tree.size.to_int_size(); let tree_size = tree.size().to_int_size();
let target_size = if size.width > size.height { let target_size = if size.width > size.height {
tree_size.scale_to_width(size.width) tree_size.scale_to_width(size.width)
@ -167,7 +157,7 @@ impl Cache {
tiny_skia::Transform::default() tiny_skia::Transform::default()
}; };
resvg::Tree::from_usvg(tree).render(transform, &mut image.as_mut()); resvg::render(tree, transform, &mut image.as_mut());
if let Some([r, g, b, _]) = key.color { if let Some([r, g, b, _]) = key.color {
// Apply color filter // Apply color filter

View file

@ -1,10 +1,9 @@
use crate::core::svg; use crate::core::svg;
use crate::core::{Color, Size}; use crate::core::{Color, Size};
use crate::graphics::text;
use crate::image::atlas::{self, Atlas}; use crate::image::atlas::{self, Atlas};
use resvg::tiny_skia; use resvg::tiny_skia;
use resvg::usvg::{self, TreeTextToPath}; use resvg::usvg;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use std::fs; use std::fs;
@ -21,7 +20,7 @@ impl Svg {
pub fn viewport_dimensions(&self) -> Size<u32> { pub fn viewport_dimensions(&self) -> Size<u32> {
match self { match self {
Svg::Loaded(tree) => { Svg::Loaded(tree) => {
let size = tree.size; let size = tree.size();
Size::new(size.width() as u32, size.height() as u32) Size::new(size.width() as u32, size.height() as u32)
} }
@ -45,38 +44,33 @@ type ColorFilter = Option<[u8; 4]>;
impl Cache { impl Cache {
/// Load svg /// Load svg
pub fn load(&mut self, handle: &svg::Handle) -> &Svg { pub fn load(&mut self, handle: &svg::Handle) -> &Svg {
use usvg::TreeParsing;
if self.svgs.contains_key(&handle.id()) { if self.svgs.contains_key(&handle.id()) {
return self.svgs.get(&handle.id()).unwrap(); return self.svgs.get(&handle.id()).unwrap();
} }
let mut svg = match handle.data() { let svg = match handle.data() {
svg::Data::Path(path) => fs::read_to_string(path) svg::Data::Path(path) => fs::read_to_string(path)
.ok() .ok()
.and_then(|contents| { .and_then(|contents| {
usvg::Tree::from_str(&contents, &usvg::Options::default()) usvg::Tree::from_str(
.ok() &contents,
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
)
.ok()
}) })
.map(Svg::Loaded) .map(Svg::Loaded)
.unwrap_or(Svg::NotFound), .unwrap_or(Svg::NotFound),
svg::Data::Bytes(bytes) => { svg::Data::Bytes(bytes) => {
match usvg::Tree::from_data(bytes, &usvg::Options::default()) { match usvg::Tree::from_data(
bytes,
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
) {
Ok(tree) => Svg::Loaded(tree), Ok(tree) => Svg::Loaded(tree),
Err(_) => Svg::NotFound, Err(_) => Svg::NotFound,
} }
} }
}; };
if let Svg::Loaded(svg) = &mut svg {
if svg.has_text_nodes() {
let mut font_system =
text::font_system().write().expect("Write font system");
svg.convert_text(font_system.raw().db_mut());
}
}
self.should_trim = true; self.should_trim = true;
let _ = self.svgs.insert(handle.id(), svg); let _ = self.svgs.insert(handle.id(), svg);
@ -127,7 +121,7 @@ impl Cache {
// It would be cool to be able to smooth resize the `svg` example. // It would be cool to be able to smooth resize the `svg` example.
let mut img = tiny_skia::Pixmap::new(width, height)?; let mut img = tiny_skia::Pixmap::new(width, height)?;
let tree_size = tree.size.to_int_size(); let tree_size = tree.size().to_int_size();
let target_size = if width > height { let target_size = if width > height {
tree_size.scale_to_width(width) tree_size.scale_to_width(width)
@ -147,8 +141,7 @@ impl Cache {
tiny_skia::Transform::default() tiny_skia::Transform::default()
}; };
resvg::Tree::from_usvg(tree) resvg::render(tree, transform, &mut img.as_mut());
.render(transform, &mut img.as_mut());
let mut rgba = img.take(); let mut rgba = img.take();

View file

@ -585,7 +585,13 @@ fn prepare(
( (
buffer.as_ref(), buffer.as_ref(),
Rectangle::new(raw.position, Size::new(width, height)), Rectangle::new(
raw.position,
Size::new(
width.unwrap_or(layer_bounds.width),
height.unwrap_or(layer_bounds.height),
),
),
alignment::Horizontal::Left, alignment::Horizontal::Left,
alignment::Vertical::Top, alignment::Vertical::Top,
raw.color, raw.color,