Giter VIP home page Giter VIP logo

swash's People

Contributors

adamnemecek avatar ajtribick avatar danielronnkvist avatar davelab6 avatar dfrg avatar dvc94ch avatar jackpot51 avatar jasper-bekkers avatar kirawi avatar nico-abram avatar ragibhasin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swash's Issues

crate-private type `Outlines<'_>` in public interface

I think there is a bug in 0.1.10:

error[E0446]: crate-private type `Outlines<'_>` in public interface
  --> ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.10/src/scale/cff/mod.rs:24:5
   |
24 | /     pub fn scale(
25 | |         &mut self,
26 | |         outlines: &outlines::Outlines,
27 | |         id: u64,
...  |
32 | |         outline: &mut Outline,
33 | |     ) -> Option<()> {
   | |___________________^ can't leak crate-private type
   |
  ::: ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swash-0.1.10/src/scale/cff/outlines.rs:39:1
   |
39 |   pub(crate) struct Outlines<'a> {
   |   ------------------------------ `Outlines<'_>` declared as crate-private

Outlines should be pub I guess instead of pub(crate).

Add support for COLRv1

Implement support for parsing version 1 of the COLR table and expose the additional data in the outline API.

Examples

It would be useful to have a minimal example of shaping some text or similar functionality. This way somebody could bootstrap themselves easier when they find the library.

Side note: incredible work. I've been waiting for a library like this for ages. Between this and rustybuzz, things are looking up.

i is not rendered properly when using JetBrains Mono

Hi!

I tried learning how swash works and I instantly jumped to the swash_demo crate. There changed the font from "times" to "JetBrains Mono" and it indeed worked (even ligatures), but for some weird reason the i was rendered incorrectly...

Example:
Screenshot 2022-11-13 at 19 05 18

Zoomed:
Screenshot 2022-11-13 at 19 05 46

no_std support?

Will this library ever add no_std support?

I ask because it's not in the Non Goals section of the README, yet it does not appear to have any allocations or use any features from libstd.

Use ttf-parser for font parsing

I see that this crate uses its own code for TTF parsing. Is there a reason why ttf-parser isn't used here? It has no dependencies and is written in exclusively safe code.

Tab ('\t') doesn't match `ClusterInfo`

I am trying to match on the whitespace enum, but it appears that parsing any kind of tab (unicode, control, etc) doesn't appear to match the Whitespace::Tab variant.

Code to reproduce:

let font_size = 16.;
let mut shape_context = ShapeContext::new();
let mut shaper = shape_context
    .builder(*font_ref)
    .script(Script::Latin)
    .size(font_size)
    .direction(Direction::LeftToRight)
    .build();

// 4 variants of how to input a `tab`
shaper.add_str("\t\u{0009}	\u{2B7E}");

shaper.shape_with(|glyph_cluster| {
    let info = glyph_cluster.info;
    println!("got INFO: '{:?}'", info.0);
    println!("got whitespace: '{:?}'", info.whitespace());
});

What it does:

got INFO: '0'
got whitespace: 'None'
got INFO: '0'
got whitespace: 'None'
got INFO: '0'
got whitespace: 'None'
got INFO: '0'
got whitespace: 'None'

What I expect it to do:

got INFO: '7'
got whitespace: 'Tab'
got INFO: '7'
got whitespace: 'Tab'
got INFO: '7'
got whitespace: 'Tab'
got INFO: '7'
got whitespace: 'Tab'

I am using the Roboto-Regular.ttf font.

"Panic: misaligned pointer reference" in rustc 1.70.0

I experienced this crash after upgrading rustc to 1.70.0, and I cannot reproduce it using rustc 1.69.0. The crash happens in an iced application (with a dependency on swash 0.1.6).

The full crash log is attached here for your information. It seems there is something wrong about the font parsing process. I tested the application in Windows Sandbox (which comes with only the fonts that Microsoft ships with Windows), so the issue should not be about the custom fonts I installed.

Full crash log
thread 'main' panicked at 'misaligned pointer dereference: address must be a multiple of 0x2 but is 0x25ace2382a5', $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\internal\parse.rs:452:13
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library\std\src\panicking.rs:578
   1: core::panicking::panic_fmt
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library\core\src\panicking.rs:67
   2: core::panicking::panic_misaligned_pointer_dereference
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library\core\src\panicking.rs:174
   3: swash::internal::parse::impl$9::from_be_data_unchecked
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\internal\parse.rs:452
   4: swash::internal::parse::FromBeData::from_be_data
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\internal\parse.rs:424
   5: swash::internal::parse::Bytes::read
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\internal\parse.rs:55
   6: swash::scale::cff::cff::IndexMetadata::unpack
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\cff\cff.rs:1191
   7: swash::scale::cff::cff::Index::new
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\cff\cff.rs:1226
   8: swash::scale::cff::cff::CffProxy::parse
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\cff\cff.rs:92
   9: swash::scale::cff::cff::CffProxy::from_font
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\cff\cff.rs:54
  10: swash::scale::proxy::ScalerProxy::from_font
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\proxy.rs:28
  11: swash::scale::impl$3::new::closure$0<swash::font::FontRef>
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\mod.rs:351
  12: swash::cache::FontCache<swash::scale::proxy::ScalerProxy>::get<swash::scale::proxy::ScalerProxy,swash::scale::impl$3::new::closure_env$0<swash::font::FontRef> >
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\cache.rs:50
  13: swash::scale::ScalerBuilder::new<swash::font::FontRef>
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\mod.rs:349
  14: swash::scale::ScaleContext::builder<swash::font::FontRef>
             at $HOME\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\swash-0.1.6\src\scale\mod.rs:325
  15: cosmic_text::swash::swash_image
             at $HOME\.cargo\git\checkouts\cosmic-text-ea4fb601986df06b\b85d6a4\src\swash.rs:32
  16: cosmic_text::swash::SwashCache::get_image_uncached
             at $HOME\.cargo\git\checkouts\cosmic-text-ea4fb601986df06b\b85d6a4\src\swash.rs:115
  17: glyphon::text_render::TextRenderer::prepare_with_depth<core::iter::adapters::filter_map::FilterMap<core::iter::adapters::zip::Zip<core::slice::iter::Iter<iced_wgpu::layer::text::Text>,core::slice::iter::Iter<u64> >,iced_wgpu::text::impl$0::prepare::closur
             at $HOME\.cargo\git\checkouts\glyphon-70ff9ac92aaa9d8a\f145067\src\text_render.rs:103
  18: glyphon::text_render::TextRenderer::prepare<core::iter::adapters::filter_map::FilterMap<core::iter::adapters::zip::Zip<core::slice::iter::Iter<iced_wgpu::layer::text::Text>,core::slice::iter::Iter<u64> >,iced_wgpu::text::impl$0::prepare::closure_env$1> >
             at $HOME\.cargo\git\checkouts\glyphon-70ff9ac92aaa9d8a\f145067\src\text_render.rs:347
  19: iced_wgpu::text::Pipeline::prepare
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\wgpu\src\text.rs:170
  20: iced_wgpu::backend::Backend::prepare_text
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\wgpu\src\backend.rs:141
  21: iced_wgpu::backend::Backend::present<alloc::string::String>
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\wgpu\src\backend.rs:99
  22: iced_wgpu::window::compositor::present<enum2$<iced_style::theme::Theme>,alloc::string::String>
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\wgpu\src\window\compositor.rs:172
  23: iced_renderer::compositor::impl$0::present::closure$0<enum2$<iced_style::theme::Theme>,alloc::string::String>
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\renderer\src\compositor.rs:122
  24: iced_graphics::renderer::Renderer<enum2$<iced_renderer::backend::Backend>,enum2$<iced_style::theme::Theme> >::with_primitives<enum2$<iced_renderer::backend::Backend>,enum2$<iced_style::theme::Theme>,enum2$<core::result::Result<tuple$<>,iced_graphics::comp
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\graphics\src\renderer.rs:51
  25: iced_renderer::compositor::impl$0::present<enum2$<iced_style::theme::Theme>,alloc::string::String>
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\renderer\src\compositor.rs:103
  26: iced_winit::application::run_instance::async_fn$0<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::Compositor<enum2$<iced_style::theme::Theme> > > >
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\winit\src\application.rs:532
  27: iced_winit::application::run::closure$1<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::Compositor<enum2$<iced_style::theme::Theme> > > >
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\winit\src\application.rs:251
  28: winit::platform_impl::platform::event_loop::impl$3::run_return::closure$0<tuple$<>,iced_winit::application::run::closure_env$1<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::Com
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop.rs:260
  29: alloc::boxed::impl$46::call_mut<tuple$<enum2$<winit::event::Event<tuple$<> > >,ref_mut$<enum2$<winit::event_loop::ControlFlow> > >,dyn$<core::ops::function::FnMut<tuple$<enum2$<winit::event::Event<tuple$<> > >,ref_mut$<enum2$<winit::event_loop::ControlFlo
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\alloc\src\boxed.rs:1980
  30: winit::platform_impl::platform::event_loop::runner::impl$3::call_event_handler::closure$0<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop\runner.rs:250
  31: core::panic::unwind_safe::impl$23::call_once<tuple$<>,winit::platform_impl::platform::event_loop::runner::impl$3::call_event_handler::closure_env$0<tuple$<> > >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\core\src\panic\unwind_safe.rs:271
  32: std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::event_loop::runner::impl$3::call_event_handler::closure_env$0<tuple$<> > >,tuple$<> >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\std\src\panicking.rs:485
  33: winit::platform_impl::platform::icon::impl$8::clone
  34: std::panicking::try<tuple$<>,core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::event_loop::runner::impl$3::call_event_handler::closure_env$0<tuple$<> > > >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\std\src\panicking.rs:449
  35: std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::event_loop::runner::impl$3::call_event_handler::closure_env$0<tuple$<> > >,tuple$<> >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\std\src\panic.rs:140
  36: winit::platform_impl::platform::event_loop::runner::EventLoopRunner<tuple$<> >::catch_unwind<tuple$<>,tuple$<>,winit::platform_impl::platform::event_loop::runner::impl$3::call_event_handler::closure_env$0<tuple$<> > >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop\runner.rs:157
  37: winit::platform_impl::platform::event_loop::runner::EventLoopRunner<tuple$<> >::call_event_handler<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop\runner.rs:242
  38: winit::platform_impl::platform::event_loop::runner::EventLoopRunner<tuple$<> >::send_event<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop\runner.rs:215
  39: winit::platform_impl::platform::event_loop::WindowData<tuple$<> >::send_event<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop.rs:142
  40: winit::platform_impl::platform::event_loop::public_window_callback_inner::closure$0<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop.rs:1125
  41: core::ops::function::FnOnce::call_once<winit::platform_impl::platform::event_loop::public_window_callback_inner::closure_env$0<tuple$<> >,tuple$<> >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\core\src\ops\function.rs:250
  42: core::panic::unwind_safe::impl$23::call_once<isize,winit::platform_impl::platform::event_loop::public_window_callback_inner::closure_env$0<tuple$<> > >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\core\src\panic\unwind_safe.rs:271
  43: std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::event_loop::public_window_callback_inner::closure_env$0<tuple$<> > >,isize>
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\std\src\panicking.rs:485
  44: std::panicking::try::do_catch<core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::window::impl$4::on_nccreate::closure_env$0<tuple$<> > >,tuple$<winit::platform_impl::platform::window::Window,winit::platform_impl::platform::event_lo
  45: std::panicking::try<isize,core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::event_loop::public_window_callback_inner::closure_env$0<tuple$<> > > >
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\std\src\panicking.rs:449
  46: std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<winit::platform_impl::platform::event_loop::public_window_callback_inner::closure_env$0<tuple$<> > >,isize>
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca\library\std\src\panic.rs:140
  47: winit::platform_impl::platform::event_loop::runner::EventLoopRunner<tuple$<> >::catch_unwind<tuple$<>,isize,winit::platform_impl::platform::event_loop::public_window_callback_inner::closure_env$0<tuple$<> > >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop\runner.rs:157
  48: winit::platform_impl::platform::event_loop::public_window_callback_inner<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop.rs:2320
  49: winit::platform_impl::platform::event_loop::public_window_callback<tuple$<> >
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop.rs:994
  50: DispatchMessageW
  51: DispatchMessageW
  52: GetClassLongW
  53: KiUserCallbackDispatcher
  54: NtUserDispatchMessage
  55: DispatchMessageW
  56: winit::platform_impl::platform::event_loop::EventLoop<tuple$<> >::run_return<tuple$<>,iced_winit::application::run::closure_env$1<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform_impl\windows\event_loop.rs:282
  57: winit::platform::run_return::impl$0::run_return<tuple$<>,iced_winit::application::run::closure_env$1<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::Compositor<enum2$<iced_style:
             at $HOME\.cargo\git\checkouts\winit-57d3141eaf559308\ac1ddfe\src\platform\run_return.rs:51
  58: iced_winit::application::platform::run<tuple$<>,iced_winit::application::run::closure_env$1<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::Compositor<enum2$<iced_style::theme::T
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\winit\src\application.rs:887
  59: iced_winit::application::run<iced::application::Instance<bin_data_inspector::App>,iced_futures::backend::null::Executor,enum2$<iced_renderer::compositor::Compositor<enum2$<iced_style::theme::Theme> > > >
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\winit\src\application.rs:226
  60: iced::application::Application::run<bin_data_inspector::App>
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\src\application.rs:208
  61: iced::sandbox::Sandbox::run<bin_data_inspector::App>
             at $HOME\.cargo\git\checkouts\iced-f01cba4d5e61fd0a\fcb1b45\src\sandbox.rs:153

The crash can be consistently reproduced on my PC with the following simple program:

use iced::{Element, Sandbox, Settings};
use iced::widget::TextInput;

struct App;

impl Sandbox for App {
    type Message = ();
    fn new() -> Self { App }
    fn title(&self) -> String { "Swash Crash".to_string() }
    fn update(&mut self, _message: Self::Message) {}
    fn view(&self) -> Element<'_, Self::Message> {
        TextInput::new("Placeholder", "Value").into()
    }
}

fn main() -> iced::Result { App::run(Settings::default()) }

with the following in Cargo.toml configuration (to use iced master):

[dependencies.iced]
git = "https://github.com/iced-rs/iced.git"
rev = "fcb1b454368638209862aeb5db41bc5f7d6d51a7"

I have already filed iced-rs/iced#1905, but I feel that this is more related to swash, so I also file a copy here.

Spacing has changed

In Neovide we determine the grid size by looking at the average glyph width and assuming that for monospace fonts, that will give us a reasonable size for a character grid.

However in your recent change, that average width has increased. Plus I think thats actually a bad metric to use because some fonts have a few very wide glyphs, so it would be incorrect to use the average glyph width.

I'm wondering if you have a better recommendation for what metric to look at. I've seen some systems pick an arbitrary character such as capital X and assume that it is representative. I've also attempted in the past to actually shape a representative piece of text and measure the spacing used there are the ground truth for the entire grid.

To be honest I don't know what the "Correct" solution is. Does swash have any metric that would work well for this use case?

AAT ligatures

Hi I'm looking at how ligatures work in the AAT morx table and I note that in fontkit it pushes the ligature glyphs back onto the stack after generating them:

https://github.com/foliojs/fontkit/blob/417af0c79c5664271a07a783574ec7fac7ebad0c/src/aat/AATMorxProcessor.js#L209

This is necessary for the Zapfino font, where the "ffi" ligature is implemented by first generating an "ff" ligature and then using that followed by the "i" to generate the "ffi" ligature, however the second ligature action won't work unless the "ff" is on the stack.

It doesn't seem that swash does this at the moment, although I haven't been able to test it with the Zapfino font yet, is there a simple shaping test program I could try?

Subpixel Format Rendering?

The subpixel format is described as "32-bit RGBA subpixel mask with 1/3 pixel offsets for the red and blue channels."

Could you elaborate on what 1/3 pixel offset means in this case? I'm not quite sure how to actually apply the subpixel mask to render text in a given color from looking at the docs (though I may have missed something obvious).

CharMap does not include substitutions

I would like to be able to cache glyphs in a font atlas at startup. The issue that I am running into is that ligature glyph IDs and other substitutions are not included in the charmap, so those characters would need to cached lazily during shaping because I cannot enumerate them upfront. Is there an easy way to enumerate the contents of the GLYF and CFF tables instead? It seems that the parsers for them are well-established but only set up to access entries by glyph ID on demand.

As a side note, navigating this codebase over the last few hours to see if I could do it myself has given me a new appreciation for how complex font handling is ๐Ÿ™ƒ. Hats off to you.

Variable font renders incorrectly

Hey!
The font Exposure from 205TF renders incorrectly with certain settings. The EXPO axis range is [-100, 100]. On swash version 0.1.12 it did not render any change on values > 0, but this seems to have been fixed between 0.1.12 and 0.1.17!

However, the issue I'm seeing now is that it renders incorrectly when the variation makes the paths cross each other. If that makes sense.

This is what it should look like with an EXPO value of 100:
Screenshot 2024-06-26 at 15 44 14

And this is what swash renders:
Screenshot 2024-06-26 at 15 44 01

๐Ÿค– and ๐Ÿชต are rendered incorrectly it would seem

Repro case

It looks like both of these render partially (I haven't tried many more, however ๐Ÿ”ฅ from the documentation seems to render correctly). The robot-man seems to have his mouth cut off, and the log seems to have the top cut off.

Since this is my very first time diving into this library, I may well be doing something wrong. I've attached the repro of what I'm trying to do.

I've also attached the rendered image below;

use swash::scale::ScaleContext;
use swash::scale::StrikeWith;
use swash::scale::*;
use zeno::Vector;

fn main() {
    use swash::FontRef;

    let font_path = "C:/Windows/Fonts/seguiemj.ttf";

    let font_data = std::fs::read(font_path).ok().unwrap();
    let font = FontRef::from_index(&font_data, 0).unwrap();

    let mut context = ScaleContext::new();
    let mut scaler = context.builder(font).hint(true).build();
    let glyph_id = font.charmap().map('๐Ÿค–');
    let image = Render::new(&[
        Source::ColorBitmap(StrikeWith::ExactSize),
        Source::ColorOutline(1),
        Source::Outline,
    ])
    .format(zeno::Format::Subpixel)
    .offset(Vector::new(0.0, 0.0))
    .render(&mut scaler, glyph_id)
    .unwrap();

    dbg!(image.placement);

    let img =
        ::image::RgbaImage::from_raw(image.placement.width, image.placement.height, image.data)
            .unwrap();
    img.save_with_format("stuff.png", ::image::ImageFormat::Png);
}

stuff

Documentation: what does "code units" means?

The documentation of the text::cluster::Token module does not explain what a code unit is. From the example code in the shape module it seems that the offset property is index of the character in the text and len its length when represented as UTF8, but is it?

In my code I don't use UTF8 strings because I have extra information and I keep an array of "chars" like this:

(char 'A') (char 'B')(kern -0.5pt)(char '๐Ÿ™ƒ')

I suppose this is three tokens but what values for offset and len should one use?

offset: 0 len: 'A'.len_utf8()
offset: 1 len: 'B'.len_utf8()
offset: 2 len: '๐Ÿ™ƒ'.len_utf8()

Should the offset of the third token be 2 (logical index into the characters) or 3 (index into my array)?

Testing swash

Hello,

I am playing with swash (and Harfbuzz too), sometimes I try to experience with algorithms and source code. However, I cannot sure whether it works for all font/script except for my limited testcases.

Does swash have testcases, test data already?

Thanks,

Correctness/Tests

You briefly mentioned this on the Reddit announcement:

Correctness is... tricky. I would like to run it against the Harfbuzz test suite, but I will have to account for differences in output both with respect to cluster numbering and how Harfbuzz distributes some positioning information differently between offsets and advances. Still, this is an area that needs attention.

I'm admittedly unqualified to understand why it's difficult to integrate the HarfBuzz test suite like rustybuzz did, but how immediate is it on your TODO list?

Tracking

  • Text Rendering Tests
  • AOT Tests
  • In-house Tests

How is it zero transient heap allocation?

This is largely because I am unfamiliar with shaping, but I'm also not that skilled in programming yet either. So, I was wondering how you achieved zero transient heap allocations. At least to me, it seems like it would cause a stack overflow if you had to shape a large amount of text. You mention a cache, but I'm still pretty confused. How does the cache work without transiently allocating to the heap?

Extract text analysis code into separate crate

The text analysis code including segmentation, cluster parsing and Unicode properties is not font dependent and should be moved to a new crate. The cluster model also needs to be updated to accommodate additional Indic scripts (specifically those with multiple pre-base forms).

Cannot render `U+1FB87 : RIGHT ONE QUARTER BLOCK`

The JetBrains Mono font does have that glyph present (which I inspected using the BirdFont font inspector), I suspect that some glyph resolution code is might be wrong somewhere, but I don't know which (trust me I tried).

I built the swash_demo from source using the following code for build_document

fn build_document() -> doc::Document {
    use layout::*;
    let mut db = doc::Document::builder();

    use SpanStyle as S;

    let underline = &[
        S::Underline(true),
        S::UnderlineOffset(Some(-1.)),
        S::UnderlineSize(Some(1.)),
    ];

    db.enter_span(&[S::family_list("JetBrains Mono"), S::Size(22.)]);
    db.add_text("๐Ÿฎ‡");
    db.leave_span();
    db.build()
}

Would be grateful if you could provide some pointers on where should I be looking for what, thanks!

Glyph selection without positioning individual glyphs

This may very well be out of scope for the library.

I'm very interested in swash as a font parsing engine for https://github.com/Kethku/neovide which is a gui for Neovim written in rust. It uses skia for rendering, but the built in harfbuzz bindings in skia leave much to be desired. Effectively Neovide is just a fancy terminal renderer which draws characters in a grid. However we use harfbuzz to select which glyphs to render for the text. This lets us combine certain glyphs into ligatures.

Currently we rely on harfbuzz to also position the glyphs, but this leads to grid positioning problems and I would like to eventually position the glyphs myself based on user config and some basic heuristics that assume fonts are monospace. The problems occur when font fallback produces a font which has different spacing from the font used to align the grid. So you get misaligned text. However if I position glyphs manually, this problem goes away.

So what would be awesome is a way to just use the glyph selection portion of the shaper rather than going through the entire shaping process. I'm not interested in the glyph positions because I'm going to place the glyphs myself on the monospace grid. I'm only interested in when a substitution is made which turns 1 or more glyphs into a single ligature, or similar such swaps. I'm not familiar with all of the types of substitutions that can be made, but I'm wondering if such a thing would be possible.

I've looked into doing this with harfbuzz, and I think it would also be possible to do it with it, but to my knowledge it would require using the clustering mechanism which I find VERY confusing. Maybe this use case could be better covered in swash? No biggy if not, just figured I'd ask.

As an aside, I would LOVE to get rid of the skia dependency all together as building it is hard and being pure rust would be badass. I've looked at pathfinder before, but was confused by the various levels at which I could integrate and eventually just went with skia as the easier thing to get myself up and running faster. You mention pathfinder in the readme as a possible renderer for swash's output. Have you done such a thing? Is there an example of such an integration? I'd be interested

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.