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:
parent
b518e30610
commit
616689ca54
10 changed files with 187 additions and 222 deletions
|
|
@ -138,11 +138,11 @@ async-std = "1.0"
|
|||
bitflags = "2.0"
|
||||
bytemuck = { version = "1.0", features = ["derive"] }
|
||||
bytes = "1.6"
|
||||
cosmic-text = "0.10"
|
||||
cosmic-text = "0.12"
|
||||
dark-light = "1.0"
|
||||
futures = "0.3"
|
||||
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"
|
||||
half = "2.2"
|
||||
image = "0.24"
|
||||
|
|
@ -157,8 +157,8 @@ ouroboros = "0.18"
|
|||
palette = "0.7"
|
||||
qrcode = { version = "0.13", default-features = false }
|
||||
raw-window-handle = "0.6"
|
||||
resvg = "0.36"
|
||||
rustc-hash = "1.0"
|
||||
resvg = "0.42"
|
||||
rustc-hash = "2.0"
|
||||
smol = "1.0"
|
||||
smol_str = "0.2"
|
||||
softbuffer = "0.4"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ impl Text {
|
|||
|
||||
let mut buffer = cosmic_text::BufferLine::new(
|
||||
&self.content,
|
||||
cosmic_text::LineEnding::default(),
|
||||
cosmic_text::AttrsList::new(text::to_attributes(self.font)),
|
||||
text::to_shaping(self.shaping),
|
||||
);
|
||||
|
|
@ -50,8 +51,10 @@ impl Text {
|
|||
let layout = buffer.layout(
|
||||
font_system.raw(),
|
||||
self.size.0,
|
||||
f32::MAX,
|
||||
None,
|
||||
cosmic_text::Wrap::None,
|
||||
None,
|
||||
4,
|
||||
);
|
||||
|
||||
let translation_x = match self.horizontal_alignment {
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ impl Cache {
|
|||
|
||||
buffer.set_size(
|
||||
font_system,
|
||||
key.bounds.width,
|
||||
key.bounds.height.max(key.line_height),
|
||||
Some(key.bounds.width),
|
||||
Some(key.bounds.height.max(key.line_height)),
|
||||
);
|
||||
buffer.set_text(
|
||||
font_system,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use std::sync::{self, Arc};
|
|||
pub struct Editor(Option<Arc<Internal>>);
|
||||
|
||||
struct Internal {
|
||||
editor: cosmic_text::Editor,
|
||||
editor: cosmic_text::Editor<'static>,
|
||||
font: Font,
|
||||
bounds: Size,
|
||||
topmost_line_changed: Option<usize>,
|
||||
|
|
@ -32,7 +32,7 @@ impl Editor {
|
|||
|
||||
/// Returns the buffer of the [`Editor`].
|
||||
pub fn buffer(&self) -> &cosmic_text::Buffer {
|
||||
self.internal().editor.buffer()
|
||||
buffer_from_editor(&self.internal().editor)
|
||||
}
|
||||
|
||||
/// Creates a [`Weak`] reference to the [`Editor`].
|
||||
|
|
@ -101,16 +101,10 @@ impl editor::Editor for Editor {
|
|||
let internal = self.internal();
|
||||
|
||||
let cursor = internal.editor.cursor();
|
||||
let buffer = internal.editor.buffer();
|
||||
|
||||
match internal.editor.select_opt() {
|
||||
Some(selection) => {
|
||||
let (start, end) = if cursor < selection {
|
||||
(cursor, selection)
|
||||
} else {
|
||||
(selection, cursor)
|
||||
};
|
||||
let buffer = buffer_from_editor(&internal.editor);
|
||||
|
||||
match internal.editor.selection_bounds() {
|
||||
Some((start, end)) => {
|
||||
let line_height = buffer.metrics().line_height;
|
||||
let selected_lines = end.line - start.line + 1;
|
||||
|
||||
|
|
@ -142,7 +136,8 @@ impl editor::Editor for Editor {
|
|||
width,
|
||||
y: (visual_line as i32 + visual_lines_offset)
|
||||
as f32
|
||||
* line_height,
|
||||
* line_height
|
||||
- buffer.scroll().vertical,
|
||||
height: line_height,
|
||||
})
|
||||
} else {
|
||||
|
|
@ -224,7 +219,8 @@ impl editor::Editor for Editor {
|
|||
Cursor::Caret(Point::new(
|
||||
offset,
|
||||
(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 {
|
||||
// Motion events
|
||||
Action::Move(motion) => {
|
||||
if let Some(selection) = editor.select_opt() {
|
||||
let cursor = editor.cursor();
|
||||
|
||||
let (left, right) = if cursor < selection {
|
||||
(cursor, selection)
|
||||
} else {
|
||||
(selection, cursor)
|
||||
};
|
||||
|
||||
editor.set_select_opt(None);
|
||||
if let Some((start, end)) = editor.selection_bounds() {
|
||||
editor.set_selection(cosmic_text::Selection::None);
|
||||
|
||||
match motion {
|
||||
// These motions are performed as-is even when a selection
|
||||
|
|
@ -272,17 +260,20 @@ impl editor::Editor for Editor {
|
|||
| Motion::DocumentEnd => {
|
||||
editor.action(
|
||||
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
|
||||
_ => editor.set_cursor(match motion.direction() {
|
||||
Direction::Left => left,
|
||||
Direction::Right => right,
|
||||
Direction::Left => start,
|
||||
Direction::Right => end,
|
||||
}),
|
||||
}
|
||||
} 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) => {
|
||||
let cursor = editor.cursor();
|
||||
|
||||
if editor.select_opt().is_none() {
|
||||
editor.set_select_opt(Some(cursor));
|
||||
if editor.selection_bounds().is_none() {
|
||||
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
|
||||
if let Some(selection) = editor.select_opt() {
|
||||
let cursor = editor.cursor();
|
||||
|
||||
if cursor.line == selection.line
|
||||
&& cursor.index == selection.index
|
||||
{
|
||||
editor.set_select_opt(None);
|
||||
if let Some((start, end)) = editor.selection_bounds() {
|
||||
if start.line == end.line && start.index == end.index {
|
||||
editor.set_selection(cosmic_text::Selection::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::SelectWord => {
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
let cursor = editor.cursor();
|
||||
|
||||
if let Some(line) = editor.buffer().lines.get(cursor.line) {
|
||||
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
|
||||
}));
|
||||
}
|
||||
}
|
||||
editor.set_selection(cosmic_text::Selection::Word(cursor));
|
||||
}
|
||||
Action::SelectLine => {
|
||||
let cursor = editor.cursor();
|
||||
|
||||
if let Some(line_length) = editor
|
||||
.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
|
||||
}));
|
||||
}
|
||||
editor.set_selection(cosmic_text::Selection::Line(cursor));
|
||||
}
|
||||
Action::SelectAll => {
|
||||
let buffer = editor.buffer();
|
||||
let buffer = buffer_from_editor(editor);
|
||||
|
||||
if buffer.lines.len() > 1
|
||||
|| buffer
|
||||
.lines
|
||||
|
|
@ -394,15 +318,20 @@ impl editor::Editor for Editor {
|
|||
.is_some_and(|line| !line.text().is_empty())
|
||||
{
|
||||
let cursor = editor.cursor();
|
||||
editor.set_select_opt(Some(cosmic_text::Cursor {
|
||||
line: 0,
|
||||
index: 0,
|
||||
..cursor
|
||||
}));
|
||||
|
||||
editor.set_selection(cosmic_text::Selection::Normal(
|
||||
cosmic_text::Cursor {
|
||||
line: 0,
|
||||
index: 0,
|
||||
..cursor
|
||||
},
|
||||
));
|
||||
|
||||
editor.action(
|
||||
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 selection = editor.select_opt().unwrap_or(cursor);
|
||||
let selection_start = editor
|
||||
.selection_bounds()
|
||||
.map(|(start, _)| start)
|
||||
.unwrap_or(cursor);
|
||||
|
||||
internal.topmost_line_changed =
|
||||
Some(cursor.min(selection).line);
|
||||
internal.topmost_line_changed = Some(selection_start.line);
|
||||
}
|
||||
|
||||
// Mouse events
|
||||
|
|
@ -466,13 +397,9 @@ impl editor::Editor for Editor {
|
|||
);
|
||||
|
||||
// Deselect if selection matches cursor position
|
||||
if let Some(selection) = editor.select_opt() {
|
||||
let cursor = editor.cursor();
|
||||
|
||||
if cursor.line == selection.line
|
||||
&& cursor.index == selection.index
|
||||
{
|
||||
editor.set_select_opt(None);
|
||||
if let Some((start, end)) = editor.selection_bounds() {
|
||||
if start.line == end.line && start.index == end.index {
|
||||
editor.set_selection(cosmic_text::Selection::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -494,7 +421,7 @@ impl editor::Editor for Editor {
|
|||
fn min_bounds(&self) -> Size {
|
||||
let internal = self.internal();
|
||||
|
||||
text::measure(internal.editor.buffer())
|
||||
text::measure(buffer_from_editor(&internal.editor))
|
||||
}
|
||||
|
||||
fn update(
|
||||
|
|
@ -517,7 +444,10 @@ impl editor::Editor for Editor {
|
|||
if font_system.version() != internal.version {
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -528,7 +458,10 @@ impl editor::Editor for Editor {
|
|||
if new_font != internal.font {
|
||||
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(
|
||||
text::to_attributes(new_font),
|
||||
));
|
||||
|
|
@ -538,7 +471,7 @@ impl editor::Editor for Editor {
|
|||
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);
|
||||
|
||||
if new_size.0 != metrics.font_size
|
||||
|
|
@ -546,7 +479,7 @@ impl editor::Editor for 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(),
|
||||
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 {
|
||||
log::trace!("Updating size of `Editor`...");
|
||||
|
||||
internal.editor.buffer_mut().set_size(
|
||||
buffer_mut_from_editor(&mut internal.editor).set_size(
|
||||
font_system.raw(),
|
||||
new_bounds.width,
|
||||
new_bounds.height,
|
||||
Some(new_bounds.width),
|
||||
Some(new_bounds.height),
|
||||
);
|
||||
|
||||
internal.bounds = new_bounds;
|
||||
|
|
@ -573,7 +506,7 @@ impl editor::Editor for Editor {
|
|||
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));
|
||||
}
|
||||
|
|
@ -585,12 +518,13 @@ impl editor::Editor for Editor {
|
|||
format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>,
|
||||
) {
|
||||
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
|
||||
.lines
|
||||
let last_visible_line = buffer.lines[scroll.line..]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, line)| {
|
||||
|
|
@ -604,7 +538,7 @@ impl editor::Editor for Editor {
|
|||
window -= visible_lines;
|
||||
None
|
||||
} else {
|
||||
Some(i)
|
||||
Some(scroll.line + i)
|
||||
}
|
||||
})
|
||||
.unwrap_or(buffer.lines.len().saturating_sub(1));
|
||||
|
|
@ -626,7 +560,7 @@ impl editor::Editor for Editor {
|
|||
|
||||
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]
|
||||
{
|
||||
let mut list = cosmic_text::AttrsList::new(attributes);
|
||||
|
|
@ -652,7 +586,7 @@ impl editor::Editor for Editor {
|
|||
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));
|
||||
}
|
||||
|
|
@ -668,7 +602,8 @@ impl PartialEq for Internal {
|
|||
fn eq(&self, other: &Self) -> bool {
|
||||
self.font == other.font
|
||||
&& 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
|
||||
.layout_opt()
|
||||
.as_ref()
|
||||
.expect("Line layout should be cached");
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or_default();
|
||||
|
||||
layout.iter().map(move |visual_line| {
|
||||
let start = visual_line
|
||||
|
|
@ -773,34 +709,61 @@ fn highlight_line(
|
|||
}
|
||||
|
||||
fn visual_lines_offset(line: usize, buffer: &cosmic_text::Buffer) -> i32 {
|
||||
let visual_lines_before_start: usize = buffer
|
||||
.lines
|
||||
let scroll = buffer.scroll();
|
||||
|
||||
let start = scroll.line.min(line);
|
||||
let end = scroll.line.max(line);
|
||||
|
||||
let visual_lines_offset: usize = buffer.lines[start..]
|
||||
.iter()
|
||||
.take(line)
|
||||
.take(end - start)
|
||||
.map(|line| {
|
||||
line.layout_opt()
|
||||
.as_ref()
|
||||
.expect("Line layout should be cached")
|
||||
.len()
|
||||
line.layout_opt().as_ref().map(Vec::len).unwrap_or_default()
|
||||
})
|
||||
.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 {
|
||||
Motion::Left => cosmic_text::Action::Left,
|
||||
Motion::Right => cosmic_text::Action::Right,
|
||||
Motion::Up => cosmic_text::Action::Up,
|
||||
Motion::Down => cosmic_text::Action::Down,
|
||||
Motion::WordLeft => cosmic_text::Action::LeftWord,
|
||||
Motion::WordRight => cosmic_text::Action::RightWord,
|
||||
Motion::Home => cosmic_text::Action::Home,
|
||||
Motion::End => cosmic_text::Action::End,
|
||||
Motion::PageUp => cosmic_text::Action::PageUp,
|
||||
Motion::PageDown => cosmic_text::Action::PageDown,
|
||||
Motion::DocumentStart => cosmic_text::Action::BufferStart,
|
||||
Motion::DocumentEnd => cosmic_text::Action::BufferEnd,
|
||||
Motion::Left => cosmic_text::Motion::Left,
|
||||
Motion::Right => cosmic_text::Motion::Right,
|
||||
Motion::Up => cosmic_text::Motion::Up,
|
||||
Motion::Down => cosmic_text::Motion::Down,
|
||||
Motion::WordLeft => cosmic_text::Motion::LeftWord,
|
||||
Motion::WordRight => cosmic_text::Motion::RightWord,
|
||||
Motion::Home => cosmic_text::Motion::Home,
|
||||
Motion::End => cosmic_text::Motion::End,
|
||||
Motion::PageUp => cosmic_text::Motion::PageUp,
|
||||
Motion::PageDown => cosmic_text::Motion::PageDown,
|
||||
Motion::DocumentStart => cosmic_text::Motion::BufferStart,
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ impl core::text::Paragraph for Paragraph {
|
|||
|
||||
buffer.set_size(
|
||||
font_system.raw(),
|
||||
text.bounds.width,
|
||||
text.bounds.height,
|
||||
Some(text.bounds.width),
|
||||
Some(text.bounds.height),
|
||||
);
|
||||
|
||||
buffer.set_text(
|
||||
|
|
@ -116,8 +116,8 @@ impl core::text::Paragraph for Paragraph {
|
|||
|
||||
internal.buffer.set_size(
|
||||
font_system.raw(),
|
||||
new_bounds.width,
|
||||
new_bounds.height,
|
||||
Some(new_bounds.width),
|
||||
Some(new_bounds.height),
|
||||
);
|
||||
|
||||
internal.bounds = new_bounds;
|
||||
|
|
|
|||
|
|
@ -439,9 +439,13 @@ impl Engine {
|
|||
let transformation = transformation * *local_transformation;
|
||||
let (width, height) = buffer.size();
|
||||
|
||||
let physical_bounds =
|
||||
Rectangle::new(raw.position, Size::new(width, height))
|
||||
* transformation;
|
||||
let physical_bounds = Rectangle::new(
|
||||
raw.position,
|
||||
Size::new(
|
||||
width.unwrap_or(clip_bounds.width),
|
||||
height.unwrap_or(clip_bounds.height),
|
||||
),
|
||||
) * transformation;
|
||||
|
||||
if !clip_bounds.intersects(&physical_bounds) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -169,7 +169,13 @@ impl Pipeline {
|
|||
font_system.raw(),
|
||||
&mut self.glyph_cache,
|
||||
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,
|
||||
alignment::Horizontal::Left,
|
||||
alignment::Vertical::Top,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use crate::core::svg::{Data, Handle};
|
||||
use crate::core::{Color, Rectangle, Size};
|
||||
use crate::graphics::text;
|
||||
|
||||
use resvg::usvg::{self, TreeTextToPath};
|
||||
use resvg::usvg;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tiny_skia::Transform;
|
||||
|
||||
|
|
@ -80,35 +79,28 @@ struct RasterKey {
|
|||
|
||||
impl Cache {
|
||||
fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> {
|
||||
use usvg::TreeParsing;
|
||||
|
||||
let id = handle.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) => {
|
||||
fs::read_to_string(path).ok().and_then(|contents| {
|
||||
usvg::Tree::from_str(
|
||||
&contents,
|
||||
&usvg::Options::default(),
|
||||
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +110,9 @@ impl Cache {
|
|||
|
||||
fn viewport_dimensions(&mut self, handle: &Handle) -> Option<Size<u32>> {
|
||||
let tree = self.load(handle)?;
|
||||
let size = tree.size();
|
||||
|
||||
Some(Size::new(
|
||||
tree.size.width() as u32,
|
||||
tree.size.height() as u32,
|
||||
))
|
||||
Some(Size::new(size.width() as u32, size.height() as u32))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
|
|
@ -147,7 +137,7 @@ impl Cache {
|
|||
|
||||
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 {
|
||||
tree_size.scale_to_width(size.width)
|
||||
|
|
@ -167,7 +157,7 @@ impl Cache {
|
|||
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 {
|
||||
// Apply color filter
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use crate::core::svg;
|
||||
use crate::core::{Color, Size};
|
||||
use crate::graphics::text;
|
||||
use crate::image::atlas::{self, Atlas};
|
||||
|
||||
use resvg::tiny_skia;
|
||||
use resvg::usvg::{self, TreeTextToPath};
|
||||
use resvg::usvg;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use std::fs;
|
||||
|
||||
|
|
@ -21,7 +20,7 @@ impl Svg {
|
|||
pub fn viewport_dimensions(&self) -> Size<u32> {
|
||||
match self {
|
||||
Svg::Loaded(tree) => {
|
||||
let size = tree.size;
|
||||
let size = tree.size();
|
||||
|
||||
Size::new(size.width() as u32, size.height() as u32)
|
||||
}
|
||||
|
|
@ -45,38 +44,33 @@ type ColorFilter = Option<[u8; 4]>;
|
|||
impl Cache {
|
||||
/// Load svg
|
||||
pub fn load(&mut self, handle: &svg::Handle) -> &Svg {
|
||||
use usvg::TreeParsing;
|
||||
|
||||
if self.svgs.contains_key(&handle.id()) {
|
||||
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)
|
||||
.ok()
|
||||
.and_then(|contents| {
|
||||
usvg::Tree::from_str(&contents, &usvg::Options::default())
|
||||
.ok()
|
||||
usvg::Tree::from_str(
|
||||
&contents,
|
||||
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.map(Svg::Loaded)
|
||||
.unwrap_or(Svg::NotFound),
|
||||
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),
|
||||
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;
|
||||
|
||||
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.
|
||||
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 {
|
||||
tree_size.scale_to_width(width)
|
||||
|
|
@ -147,8 +141,7 @@ impl Cache {
|
|||
tiny_skia::Transform::default()
|
||||
};
|
||||
|
||||
resvg::Tree::from_usvg(tree)
|
||||
.render(transform, &mut img.as_mut());
|
||||
resvg::render(tree, transform, &mut img.as_mut());
|
||||
|
||||
let mut rgba = img.take();
|
||||
|
||||
|
|
|
|||
|
|
@ -585,7 +585,13 @@ fn prepare(
|
|||
|
||||
(
|
||||
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::Vertical::Top,
|
||||
raw.color,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue