pop-os / cosmic-text Goto Github PK
View Code? Open in Web Editor NEWPure Rust multi-line text handling
Home Page: https://pop-os.github.io/cosmic-text/cosmic_text/
License: Apache License 2.0
Pure Rust multi-line text handling
Home Page: https://pop-os.github.io/cosmic-text/cosmic_text/
License: Apache License 2.0
I'm on macOS 13.2.1, with M1. When I run the editor-libcosmic
example, the text looks blurry compared to native text. Some time ago I head this issue with nuklear
. It was related to antialiasing. (Notice also on the screenshot some symbols aren't rendered, but I'm not sure whether it's related to cosmic-text
.)
Hi! I'm quite excited for this library.
I'm a big fan of super lean build times so I try to audit dependencies to find areas to improve. In this case it seems unicode-linebreak
implements a rather chunky build.rs
script that makes it your second slowest building dependency (after swash
).
xi-unicode
pre-bakes the unicode tables without a build.rs so it builds much faster.
Swapping is an easy one-line change:
Change this line:
cosmic-text/src/font/matches.rs
Line 246 in ac83f58
to this:
for (end_lb, _) in xi_unicode::LineBreakIterator::new(span) {
Alongside the obvious cargo.toml
changes.
Edit: I ran editor-test
and it reported "All lines matched!". I haven't ran further tests.
When calling layout
with Wrap::None
, the w
property of VisualLine
is not updated, which breaks alignment options such as Align::center
:
Lines 664 to 670 in bfb5eef
Besides, I don't really understand why Wrap::None
has to be handled differently from other wrapping options. I might be wrong here, but wouldn't replacing fit_x - word_width >= 0.
with wrap == Wrap::None || fit_x - word_width >= 0.
inside the second branch be sufficient? Is this done for performance reasons?
I see #43 added support for constructing a FontSystem with custom fonts loaded, but is there a way to get a mutable reference to the font database after the system is constructed so that more fonts can be loaded afterwards?
It's possible that remaining_len
attempts to subtract 1 from 0 in certain cases (I ran into it when testing font sizes in my application).
Line 241 in 9a4d067
I think it might happen when the layout line can't into the dimensions or something similar. I'll work on simplifying my test case down to verify but wanted to create this issue so I don't forget about it.
There is an issue with numbers inside a mixed RTL/LTR sentence. Currently a span only contains a boolean that says if it is RTL or LTR. To get a correct layout we need to also consider the BidiClass. Some Bidi Class values are strong LTR or RTL, but some are Weak or Neutral which means when we are creating the layout although the span might be written LTR for layouting purposes it should be treated as an RTL span (if the surrounding text is also RTL).
The simplest example is numbers. Consider the following example:
The latest version of Pop OS is 22.04. آخرین ورژن سیستم عامل پاپ ۲۲.۰۴ است.
This is currently rendered like this:
As you can see the numbers in the RTL span are treated as an LTR span which causes the layout to mess up.
When running the examples I get very frequent (dozens per second) log messages like that:
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'Noto Sans'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'DejaVu Sans'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'FreeSans'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'Noto Sans Mono'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'DejaVu Sans Mono'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'FreeMono'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'Noto Sans Symbols'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] failed to find family 'Noto Sans Symbols2'
[2023-06-04T20:40:18Z DEBUG cosmic_text::font::fallback] Failed to find preset fallback for [] locale 'en-US', used 'Verdana': 'Word'
It seems like the library is constantly trying to resolve fallback fonts instead of doing it once and caching the outcome.
The resulting performance is extremely bad as well. For example, I need to run the editor in release mode for it to be somewhat responsive.
I'm on macOS 13.2.1, with M1. When I run the example and open sample/hello.txt
and trying to change the font size to Title 4 the application panics with:
thread 'main' panicked at 'attempt to subtract with overflow', src/shape.rs:711:37
The issue appears only on debug build.
In the example of using Fira Sans and having an fi ligature, moving to the middle does not show a cursor.
MRE:
// cosmic-text = "0.7.0"
use cosmic_text::{Attrs, Buffer, FontSystem, Metrics};
fn main() {
let font_system = FontSystem::new();
let metrics = Metrics::new(14, 20);
let mut buffer = Buffer::new(&font_system, metrics);
buffer.set_size(80, 25);
let attrs = Attrs::new();
let message = "A\rB"; // Problem!
buffer.set_text(message, attrs);
}
Discovered while trying to develop an X11 application- the Enter key sent a "\r" instead of a "\n", which my prototype application (not using Editor
) simply appended to the end of the rendered buffer, causing a crash when the next character was appended.
The cause seems to be that \r
is treated as a paragraph separator by unicode-bidi
, but not by the lines
iterator from std uses to do paragraph separator in buffer.set_text()
, so when the paragraph is sent to be shaped it's split into two paragraphs and triggers the assert.
Rustybuzz is very accurate text shaping library, but as they say in their own readme, their implementation is slower than HarfBuzz. Swash also provides high quality text shaping while being more performant than rustybuzz, though it is still a bit unstable and has some bugs.
It doesn't seem to be implemented at the moment, so why not make a feature that uses swash for shaping instead of rustybuzz?
The main use case here is being able to reuse a Buffer both for layout and drawing. iced
does not know the color of the text during layout.
Color doesn't really affect anything but drawing, right? It seems it'd make more sense to provide a list of color spans as an argument to draw? Or maybe we could change BufferLine::set_attrs_list
to not trigger a reset if only the colors differ?
cosmic-text/src/buffer_line.rs
Lines 69 to 72 in f92a205
It seems like font fallback generally works pretty well, but if a certain property, such as italics are not available for the fallback font, the font is not chosen at all and tofus are rendered instead.
Here's an example where Calibri is the main font. Calibri by itself does not support Hangul, so it falls back to a different font (seems to be Malgun Gothic). This works fine until you choose Calibri Italic, at which point it can't find an italic version of Malgun Gothic and shows tofus.
This may or may not be related to #58. I'm surprised the fallback is rejected if found in the first place though, so it may not actually be related.
It's often the case that UIs want to intersperse non-textual content in line with text. Examples of this would include inline images and form fields. But in theory this extends to arbitrary content. It seems to me that:
I don't really care what the API looks like, but I would suggest something like:
Vec<InlineBox>
as input in addition to it's existing inputsInlineBox
consists of:
width
height
x
positiony
positionReproduction: https://github.com/tigregalis/cosmic-text-width-constraint-bug
When we draw text in Bevy, we currently do 2+ "size" passes (1+ node measurement pass during layout, and 1 rendering pass); the calculated width from the first pass determines the size of the node.
A rare bug(?) occurs when laying out the text (6) SomewhatBoringDisplayTransform
with a font size of 18.0
pixels and the font FiraMono-Medium.ttf
. This shows up in a specific Bevy example, and I haven't been able to reproduce it with other text / font sizes / fonts, but the possibility exists.
We lay out this text in a buffer (buffer1
) with an UNBOUNDED
size; the buffer has one line (one layout run) with a certain width1
(run.line_w
).
Later, we lay out the same line in a buffer (buffer2
) with a maximum size of width1
pixels wide.
That is, the first buffer's width determines the width constraint of the second buffer. I expected that they would produce the same result.
However, this second buffer (buffer2
) is not considered wide enough to fit that text, so the second word breaks onto a second line.
Even ceil
ing the width still causes it to break. However, ceil
ing it and adding some small value (e.g. 0.001
) gets around this behaviour.
I'd like to be able to access the underlying Database
in a FontSystem
mutably, so I can easily add fonts without needing to convert to the underlying Database
and back.
However, the Database
is currently self-referentially borrowed for caching the font-ID-to-font relationship. It looks like this is due to the font lookup in fontdb
being an O(n)
process. RazrFalcon/fontdb#47 would fix that problem and allow us to solve this issue.
Depending on whether it's a mixed layout or not, the arabic characters are either reversed or not:
This is with the latest master.
Here you see a debugger view of just the arabic characters:
This may or may not be intended, but is super weird to deal with. To properly handle this I need to properly mix the shape line's BIDI level with the shape span's BIDI level and then depending on what combination it is, iterate the glyphs in reverse or not.
I don't even understand why cosmic-text (sometimes) reverses what rustybuzz spits out in the first place, as I need to unreverse it to draw the glyphs in the proper order. That seems like a lot of wasted work that cosmic-text does.
fontdb
version 0.14 contains a breaking change that allows one to get the IDs from a font that was just registered, which helps when it comes to implementing a "load font family" function. It would be nice to bump the version of this crate. Since this would be a breaking change, I understand if it's not high priority; it should probably be bundled with another breaking change once the time comes.
I'm on macOS 13.2.1, with M1. When I run examples, I get something like this:
svg icon 'Name("format-justify-left")' size 20 not found
svg icon 'Name("format-justify-center")' size 20 not found
svg icon 'Name("format-justify-right")' size 20 not found
svg icon 'Name("format-justify-fill")' size 20 not found
Running editor-libcosmic
looks like this:
Currently you have to set the Buffer dimensions before shaping. But it is common requirement to size a box containing some text based on the size of the text itself. It would therefore be great if it were possible to shape/layout with one or both dimensions being unset/infinite (it should be possible to independently set each dimension to infinite).
This could be represented with an Option<i32>
(or Option<u32>
- does a negative buffer size make sense?) or possibly just an f32
, making use of the floating point Infinity
value.
Hi y'all,
I was just trying out this project on my Fedora 36 machine. I managed to run the examples after installing the dependencies with dnf install SDL2-devel SDL2-static
and exporting RUSTFLAGS="-Lnative=/usr/lib64/"
. It'd be cool if you could mention that in the README so that others don't run into the same issue as me.
Thanks for the cool project.
Hi! First of all, thanks for the crate!
I was trying to run the examples but faced some issues and I was wondering
Would accept PRs to improve them?
The issues I faced are the following. Some of them are from the "first-user perspective", I just want to help.
terminal
example uses termion
, which does not compile on Windows... So I could not run it.editor-orbclient
example compiles, but panic with [2022-11-23T10:09:18Z ERROR editor_orbclient] failed to load "": The system cannot find the path specified.
editor-libcosmic
example failed to build because xdg::BaseDirectories
was not found.(I am on Windows running rustc 1.64.0
)
Some preliminary thoughts about these issues are the following.
terminal
example uses termion
modules color
and cursor
. A more platform-friendly crate with these features may be console
. It also ranks higher in https://lib.rs/std so I thought the change would be an improvement.I have not checked the other examples in detail yet.
Running:
cargo clean
cargo run
I crashes at startup:
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Running `/home/hugo/src/github.com/pop-os/cosmic-text/target/debug/editor-libcosmic`
svg icon 'Name("format-justify-left")' size 20 not found
svg icon 'Name("format-justify-center")' size 20 not found
svg icon 'Name("format-justify-right")' size 20 not found
svg icon 'Name("format-justify-fill")' size 20 not found
thread 'main' panicked at 'misaligned pointer dereference: address must be a multiple of 0x2 but is 0x7ffa320c4413', /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/internal/parse.rs:452:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'panic in a function that cannot unwind', library/core/src/panicking.rs:126:5
stack backtrace:
0: 0x55723dbc2e6a - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hdf22feec95880e0d
1: 0x55723dbe754f - core::fmt::write::h235c37951d00a89c
2: 0x55723dbbfb65 - std::io::Write::write_fmt::h9bc27794617a6db9
3: 0x55723dbc2c35 - std::sys_common::backtrace::print::h88a8b0be3878a062
4: 0x55723dbc42de - std::panicking::default_hook::{{closure}}::h6164333d411d28b9
5: 0x55723dbc4085 - std::panicking::default_hook::hab575ecd0a58206d
6: 0x55723dbc483e - std::panicking::rust_panic_with_hook::h00441c5461358113
7: 0x55723dbc46f2 - std::panicking::begin_panic_handler::{{closure}}::ha10326a5adba7763
8: 0x55723dbc32d6 - std::sys_common::backtrace::__rust_end_short_backtrace::he5fc416511606524
9: 0x55723dbc4492 - rust_begin_unwind
10: 0x55723c427f83 - core::panicking::panic_nounwind_fmt::hc94c7db7a384e0e4
11: 0x55723c428031 - core::panicking::panic_nounwind::h3073504210c4b8f8
12: 0x55723c4281c3 - core::panicking::panic_cannot_unwind::hc75b58def32de0a1
13: 0x55723cbf9aff - <u16 as swash::internal::parse::FromBeData>::from_be_data_unchecked::h99595792a7416591
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/internal/parse.rs:450:5
14: 0x55723cbf9aff - <i16 as swash::internal::parse::FromBeData>::from_be_data_unchecked::h446e05bc48a6d378
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/internal/parse.rs:461:9
15: 0x55723cbf935c - swash::internal::parse::Stream::read::h66d836185c5a71d4
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/internal/parse.rs:216:30
16: 0x55723cb59eaf - swash::scale::glyf::scale::Scaler::load::h03a8f82d972ac272
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/scale/glyf/scale.rs:118:33
17: 0x55723cb58d1b - swash::scale::glyf::scale::Scaler::scale::h535ce8c014dd64a7
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/scale/glyf/scale.rs:39:9
18: 0x55723cc0c5b0 - swash::scale::Scaler::scale_outline_impl::he8b445a1ba1b85e7
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/scale/mod.rs:560:20
19: 0x55723cc0e2e7 - swash::scale::Render::render_into::h0933b9ca6121aa40
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/scale/mod.rs:842:24
20: 0x55723cc0e7fd - swash::scale::Render::render::hda4c73187d0bed4f
at /home/hugo/.local/state/cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.6/src/scale/mod.rs:974:12
21: 0x55723ca93101 - cosmic_text::swash::swash_image::hc33a1cf5f4537c4d
at /home/hugo/.local/state/cargo/git/checkouts/cosmic-text-92dc585b4973ff15/e788c17/src/swash.rs:43:5
22: 0x55723ca933d4 - cosmic_text::swash::SwashCache::get_image::{{closure}}::h8fa25964bd3b858b
at /home/hugo/.local/state/cargo/git/checkouts/cosmic-text-92dc585b4973ff15/e788c17/src/swash.rs:126:32
23: 0x55723ca94e0a - std::collections::hash::map::Entry<K,V>::or_insert_with::h94a2f9259e3403a4
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/collections/hash/map.rs:2558:43
24: 0x55723ca93394 - cosmic_text::swash::SwashCache::get_image::hbf3e517cabb9f625
at /home/hugo/.local/state/cargo/git/checkouts/cosmic-text-92dc585b4973ff15/e788c17/src/swash.rs:124:9
25: 0x55723c96e0e0 - iced_softbuffer::surface::draw_primitive::h0970a481c3b4741e
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/softbuffer/src/surface.rs:287:42
26: 0x55723c4761f4 - iced_softbuffer::surface::Surface::present::{{closure}}::h5e9b10fd95213aef
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/softbuffer/src/surface.rs:80:21
27: 0x55723c5006fa - iced_graphics::renderer::Renderer<B,T>::with_primitives::h780b7d08389fe880
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/graphics/src/renderer.rs:51:9
28: 0x55723c4760cb - iced_softbuffer::surface::Surface::present::hb0ae66d43477e711
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/softbuffer/src/surface.rs:78:13
29: 0x55723c511775 - <iced_softbuffer::window::compositor::Compositor<Theme> as iced_graphics::window::compositor::Compositor>::present::h9ee1693909a5e7fb
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/softbuffer/src/window/compositor.rs:77:9
30: 0x55723c450e48 - iced_winit::application::run_instance::{{closure}}::hec88d22234ccea44
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/winit/src/application.rs:458:23
31: 0x55723c453ba9 - iced_winit::application::run::{{closure}}::h45de27d32162e4bb
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/winit/src/application.rs:224:24
32: 0x55723c5038e1 - winit::platform_impl::platform::sticky_exit_callback::hdb4634255939e89d
at /home/hugo/.local/state/cargo/git/checkouts/winit-40d7deb2b0c08730/d35712b/src/platform_impl/linux/mod.rs:854:9
33: 0x55723c4d5411 - winit::platform_impl::platform::wayland::event_loop::EventLoop<T>::run_return::h6cf7ad6e506a868c
at /home/hugo/.local/state/cargo/git/checkouts/winit-40d7deb2b0c08730/d35712b/src/platform_impl/linux/wayland/event_loop/mod.rs:529:21
34: 0x55723c502bcd - winit::platform_impl::platform::EventLoop<T>::run_return::h3df2a42843711a4b
at /home/hugo/.local/state/cargo/git/checkouts/winit-40d7deb2b0c08730/d35712b/src/platform_impl/linux/mod.rs:753:56
35: 0x55723c436eaa - <winit::event_loop::EventLoop<T> as winit::platform::run_return::EventLoopExtRunReturn>::run_return::hcb4fc8f721868fbc
at /home/hugo/.local/state/cargo/git/checkouts/winit-40d7deb2b0c08730/d35712b/src/platform/run_return.rs:62:9
36: 0x55723c48340d - iced_winit::application::platform::run::h478018cc34c91229
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/winit/src/application.rs:776:17
37: 0x55723c45371a - iced_winit::application::run::h10c3b95d5ebd8873
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/winit/src/application.rs:199:5
38: 0x55723c49e4c6 - iced::application::Application::run::h074aaf50cb55273c
at /home/hugo/.local/state/cargo/git/checkouts/libcosmic-b367e32ffc370f4f/035ec88/iced/src/application.rs:216:12
39: 0x55723c4fa8bd - editor_libcosmic::main::had6a56cb3faf4b8b
at /home/hugo/src/github.com/pop-os/cosmic-text/examples/editor-libcosmic/src/main.rs:81:5
40: 0x55723c4ac8b2 - core::ops::function::FnOnce::call_once::h9a5a7cdd054932c7
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/ops/function.rs:250:5
41: 0x55723c4c65b5 - std::sys_common::backtrace::__rust_begin_short_backtrace::hcfa98379b0a7c986
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:134:18
42: 0x55723c4e6c06 - std::rt::lang_start::{{closure}}::hedf5d57ef652265b
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/rt.rs:166:18
43: 0x55723dbba5b2 - std::rt::lang_start_internal::h1181aa36d76c1285
44: 0x55723c4e6bda - std::rt::lang_start::hb4772950ea42ef68
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/rt.rs:165:17
45: 0x55723c4ff1fe - main
46: 0x7ffa37499880 - libc_start_main_stage2
at /home/buildozer/aports/main/musl/src/1.2.4/src/env/__libc_start_main.c:95:2
thread caused non-unwinding panic. aborting.
zsh: abort cargo run
Current HEAD is 2c8d7c0bb9b486b75b8282a66fb25afc0c4fdc17
.
I'm on alpine, using the system compiler:
> rustc --version
rustc 1.70.0 (90c541806 2023-05-31) (Alpine Linux 1.70.0-r3)
> rustup show
Default host: x86_64-unknown-linux-musl
rustup home: /home/hugo/.local/state/rustup
installed toolchains
--------------------
nightly-x86_64-unknown-linux-musl
system (default)
active toolchain
----------------
system (default)
rustc 1.70.0 (90c541806 2023-05-31) (Alpine Linux 1.70.0-r3)
> cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.18.0
PRETTY_NAME="Alpine Linux v3.18"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
I'm not entirely sure if the issue is in libcosmic itself, or a dependency.
Allow something similar to CSS writing-mode to be set on a buffer: https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
editor-test.sh
fails on
[2022-10-24T21:59:35Z DEBUG editor_test] Line " STARGΛ\u{30a}TE SG-1, a = v\u{307} = r\u{308}, a\u{20d1} ⊥ b\u{20d1}"
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `TextCursor { line: TextLineIndex(57), index: 9 }`,
right: `TextCursor { line: TextLineIndex(57), index: 7 }`', examples/editor-test/src/main.rs:129:17
stack backtrace:
0: 0x5631652662bd - std::backtrace_rs::backtrace::libunwind::trace::h9135f25bc195152c
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
1: 0x5631652662bd - std::backtrace_rs::backtrace::trace_unsynchronized::h015ee85be510df51
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x5631652662bd - std::sys_common::backtrace::_print_fmt::h5fad03caa9652a2c
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys_common/backtrace.rs:66:5
3: 0x5631652662bd - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h2b42ca28d244e5c7
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys_common/backtrace.rs:45:22
4: 0x5631652830ac - core::fmt::write::h401e827d053130ed
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/fmt/mod.rs:1198:17
5: 0x563165263e21 - std::io::Write::write_fmt::hffec93268f5cde32
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/io/mod.rs:1672:15
6: 0x563165267995 - std::sys_common::backtrace::_print::h180c4c706ee1d3fb
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys_common/backtrace.rs:48:5
7: 0x563165267995 - std::sys_common::backtrace::print::hd0c35d18765761c9
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys_common/backtrace.rs:35:9
8: 0x563165267995 - std::panicking::default_hook::{{closure}}::h1f023310983bc730
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:295:22
9: 0x5631652676b1 - std::panicking::default_hook::h188fec3334afd5be
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:314:9
10: 0x563165267f26 - std::panicking::rust_panic_with_hook::hf26e9d4f97b40096
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:698:17
11: 0x563165267e17 - std::panicking::begin_panic_handler::{{closure}}::hfab912107608087a
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:588:13
12: 0x5631652667b4 - std::sys_common::backtrace::__rust_end_short_backtrace::h434b685ce8d9965b
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys_common/backtrace.rs:138:18
13: 0x563165267b49 - rust_begin_unwind
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:584:5
14: 0x563164ff5033 - core::panicking::panic_fmt::ha6dc7f2ab2479463
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/panicking.rs:142:14
15: 0x563165281d08 - core::panicking::assert_failed_inner::h433285798fdd5aeb
16: 0x563164fee9cb - core::panicking::assert_failed::h06cf6ad39bd1347f
17: 0x563164ff701a - editor_test::main::h25866e9413ee35c9
18: 0x563164ff75a3 - std::sys_common::backtrace::__rust_begin_short_backtrace::h0afbcc2875b404f1
19: 0x563164ff7779 - std::rt::lang_start::{{closure}}::h6671d31bbca3e562
20: 0x56316525f45e - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hcdfee62722e5e4b8
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/ops/function.rs:280:13
21: 0x56316525f45e - std::panicking::try::do_call::h84ca51609826746f
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:492:40
22: 0x56316525f45e - std::panicking::try::hd58075e533b8e0cb
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:456:19
23: 0x56316525f45e - std::panic::catch_unwind::h1ebac24d83cb6ce2
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panic.rs:137:14
24: 0x56316525f45e - std::rt::lang_start_internal::{{closure}}::h0145388a1edd1640
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/rt.rs:128:48
25: 0x56316525f45e - std::panicking::try::do_call::h7630182e534a0a32
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:492:40
26: 0x56316525f45e - std::panicking::try::h05b6544f0c6331dc
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:456:19
27: 0x56316525f45e - std::panic::catch_unwind::h77b2ba8fd3309f34
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panic.rs:137:14
28: 0x56316525f45e - std::rt::lang_start_internal::h6612c8a7a6861b8b
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/rt.rs:128:20
29: 0x563164ff7222 - main
30: 0x7f1d989f2d90 - <unknown>
31: 0x7f1d989f2e40 - __libc_start_main
32: 0x563164ff52d5 - _start
33: 0x0 - <unknown>
On my system (Xubuntu), running FontSystem::new()
takes a significant amount of time. On release, it takes around a second to run. On debug, it takes up to ten seconds.
There should probably be some measures taken to make sure FontSystem
runs quickly. However, it should also be noted somewhere that FontSystem
takes a while to load.
TrueType provides at least:
sbix
CBDT
+ CBLC
svg
COLR
v0 and v1Will need a winit
example to experiment with this
Excerpt of cargo bloat
when run on an example programming containing winit
and piet-hardware
, which uses cosmic-text
for text:
File .text Size Crate Name
0.6% 2.1% 77.7KiB x11_dl x11_dl::xlib::Xlib::open::{{closure}}
0.2% 0.7% 27.8KiB swash swash::scale::bitmap::resize
0.2% 0.6% 23.6KiB swash swash::scale::glyf::hint::Hinter::execute
0.2% 0.6% 22.3KiB std addr2line::ResDwarf<R>::parse
0.2% 0.6% 22.3KiB winit winit::platform_impl::platform::wayland::event_loop::EventLoop<T>::run
0.2% 0.5% 20.1KiB glow glow::gl46::struct_commands::GlFns::load_all_with_dyn
0.2% 0.5% 19.9KiB std std::backtrace_rs::symbolize::gimli::resolve::{{closure}}
0.1% 0.5% 17.4KiB winit winit::platform_impl::platform::x11::event_processor::EventProcessor<T>::process_event
0.1% 0.4% 14.8KiB cosmic_text cosmic_text::shape::ShapeLine::layout
0.1% 0.4% 14.6KiB piet piet::samples::samples_main
0.1% 0.4% 14.2KiB png png::decoder::stream::StreamingDecoder::update
0.1% 0.3% 13.0KiB wayland_sys wayland_sys::client::WaylandClient::open
0.1% 0.3% 13.0KiB ttf_parser ttf_parser::tables::cff::cff1::_parse_char_string
0.1% 0.3% 13.0KiB ttf_parser ttf_parser::tables::cff::cff1::_parse_char_string
0.1% 0.3% 12.6KiB glutin_winit glutin_winit::finalize_window
0.1% 0.3% 12.2KiB winit winit::platform_impl::platform::x11::window::UnownedWindow::new
0.1% 0.3% 11.5KiB ttf_parser ttf_parser::tables::cff::cff2::_parse_char_string
0.1% 0.3% 11.5KiB ttf_parser ttf_parser::tables::cff::cff2::_parse_char_string
0.1% 0.3% 11.1KiB swash swash::scale::cff::cff::Glyph::parse_imp
0.1% 0.3% 10.8KiB smithay_client_toolkit smithay_client_toolkit::seat::keyboard::ffi::XkbCommon::open
The CFF font parsing tables from ttf_parser
add about 50 KiB to the binary while the one that swash
uses adds about 12 KiB to the binary. It would be nice if only one instance of the CFF table was present in the final binary.
This is a highly requested feature from a rich text editor - being able to change font size within a line.
I looked into doing this myself but couldn't figure out a good way to get the attrs into layout without adding a font size field to the shaping structs, which seemed to be against the spirit of the design. If there's any advice on what changes would need to be made where to make this happen, I'll gladly do it.
Having the glyph cache inside of cosmic-text wastes memory if the image will be immediately uploaded to GPU, and the API returning pixel positions and colors instead of images decreases performance.
I try to utilize cosmic-text
to draw text to a bitmap and to obtain a tight bounding box around the result. Right now, I am confused by the calculation of the vertical offset of the text. To elaborate further, let us assume that we draw a single glyph, i.e. the letter "g"
, using a Buffer
. For the sake of simplicity, we set line_height == font_size == 72.0
(i.e. we do not apply leading aka additional distance between the lines). When we call Buffer::draw()
, the code first creates a LayoutRunIter
whose line_y
property is initialized as follows:
Line 215 in bfb5eef
In our case, y_offset()
evaluates to 0.0
(no leading, see above) and therefore, our run starts at a vertical offset of 0.0
. Now, we call next()
on the iterator to draw the first run and observe that line_y
is incremented by the line height which is equal to the font size (aka 72.0
):
Line 241 in bfb5eef
Finally, we obtain the glyph image from `swash' and draw it to the given offset:
Lines 718 to 720 in bfb5eef
run.line_y
still evaluates to 72.0
in our example. However, if I understand correctly, the swash
image is positioned relatively to the baseline of the glyph. I did not find explicit confirmation for this assumption in the swash
documentation, but the swash_demo repo provides an extensive sample for this. When drawing its layout, it incorporates the baseline into the vertical offset as seen here:
https://github.com/dfrg/swash_demo/blob/55aedbc8604201f1b4925e2b986db59b838dc062/src/main.rs#L493
In opposition, cosmic-text
effectively places the baseline at the bottom of the line. When I try to draw my "g"
glyph to the top-left corner of a bitmap and set my bounding box height to 72 pix
, I end up with the following result:
How to fix this? I am not adept in typography, but for my understanding, the vertical offset must be corrected by the descent of the font as displayed here:
Indeed, to draw my glyphs to the bitmap, I tried to calculate the baseline of the font by myself to apply this correction. This approach works, but cosmic-text
makes it pretty hard to implement it. Basically, I have to layout my line, obtain the FontID
from the glyphs, query the Font
from the FontSystem
and do something like this:
let metrics = font.as_swash().metrics(&[]);
let total_height = metrics.ascent + metrics.descent;
let baseline = font_size * metrics.ascent / total_height;
In fact, this is about the same calculation that is done in the swash
demo, see here:
By using baseline
instead of font_size
(resp. the total line height) as vertical offset, I finally get the correct result. I can live with this approach, but it would be nice if cosmic-text
made it easier for me to access the baseline offsets of the layout lines.
Sorry for the long explanation. I hope the issue has been made clear - and thanks for your awesome work on this crate!
It would be useful to have a way to output vector paths as an alternative to rendering pixels to an image.
Do you plan to support fake bold and fake italic?
Originally I found this issue in the advanced text branch for iced. My system reports that 96.8MB is used when running. It seems like a bit much to use that much memory for just displaying some text. Iced gave memory usage of around 100MB for the checkbox example on the advanced-text branch.
I ran dhat from valgrind for iced and it seems that some parts of rustybuzz appears to be the cause of 12MB of memory usage.
I am running on Linux on aarch64.
I am currently developing a cosmic-text
-based implementation of the piet
text API, see here. The only bits from piet
that are currently unimplemented are variable font sizes (already raised in #64) and text justification.
piet
expects there to be utilities for text justification, with start (default), right, center and justified alignments. See this enum for more information.
Are there any plans to add text alignment to cosmic-text
?
While it is possible to use i32::MAX
if there is no height limit for a Buffer
, the resulting Buffer
will use i32::MAX
as the final dimension. This means that Buffer::visible_lines
will not be very useful.
I think it'd be more useful to let layouting dictate the final height
of a Buffer
.
cosmic-text
currently implements a very basic 1:1 matching algorithm where if anything doesn't perfectly match, the font will never be chosen:
Lines 166 to 175 in b9fef72
It should implement the CSS Fonts Module Level 3 - 5. Font Matching Algorithm.
Also it's super odd how Emoji is considered the fallback font and not the actual specified fallback font.
Hi there,
I attempted to build editor-libcosmic
under examples, but I get the following error:
--- stderr
`"pkg-config" "--libs" "--cflags" "gdk-3.0" "gdk-3.0 >= 3.18"` did not exit successfully: exit status: 1
error: could not find system library 'gdk-3.0' required by the 'gdk-sys' crate
I kept reading this as gtk-3.0
, but I realized it says gdk and I looked around for that package and couldn't find it on the ubuntu repos. I'm sure I'm missing something super simple, so sorry if this one is obvious.
Info about my system:
NAME="Pop!_OS"
VERSION="22.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"
PRETTY_NAME="Pop!_OS 22.04 LTS"
VERSION_ID="22.04"
HOME_URL="https://pop.system76.com"
SUPPORT_URL="https://support.system76.com"
BUG_REPORT_URL="https://github.com/pop-os/pop/issues"
PRIVACY_POLICY_URL="https://system76.com/privacy"
VERSION_CODENAME=jammy
UBUNTU_CODENAME=jammy
LOGO=distributor-logo-pop-os
NVIDIA Corporation TU116M [GeForce GTX 1660 Ti Mobile]
Thanks in advance
Hi, I'm from the ICU4X team. We're an open source project building i18n components in Rust.
I noticed in your README that you support "basic" line layout. If you need to support full UAX 14 line break, including models for Southeast Asian languages, I wanted to suggest ICU4X, the icu_segmenter crate.
icu4x.unicode.org
I'm trying to add support for WASM to my piet-cosmic-text
crate by embedding a font into the executable. However, it seems that, even after I set the font using set_sans_serif_font
on the fontdb::Database
, I get this panic:
panicked at 'no default font found', /home/jtnunley/.cargo/registry/src/github.com-1ecc6299db9ec823/cosmic-text-0.8.0/src/shape.rs:130:33
It would be nice to be able to set the fallback font to something such that it can be used in the event where none are available.
Currently only the primary system locale is used. Allow the use of secondary system locales for resolving Han unification and other things, and also allow a span of text to be given an explicit locale.
Modifying editor-test
let text = if let Some(arg) = env::args().nth(1) {
fs::read_to_string(&arg).expect("failed to open file")
} else {
#[cfg(feature = "mono")]
let default_text = include_str!("../../../sample/a.txt");
#[cfg(not(feature = "mono"))]
let default_text = include_str!("../../../sample/a.txt");
default_text.to_string()
};
and putting to sample file - ss.txt.zip
crash app with info
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `Cursor { line: 0, index: 11747, affinity: After }`,
right: `Cursor { line: 0, index: 11743, affinity: After }`', examples/editor-test/src/main.rs:99:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Is planned/supported?
Replace all Range driven Vecs with a Btree using https://crates.io/crates/rangemap
This should boost performance. I am currently Added the missing derives we need in a PR for rangemap. If they don't add them we can remake the library into something else worse case.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.