Skip to content

Spans with different fonts render as same font unless there are space characters #445

@rparrett

Description

@rparrett

Version tested

latest main. bisected to #407

Problem

"Comic" should be in Comic Neue.

Image

Repro

Run the following code, adapted from the rich-text example.

main.rs
// SPDX-License-Identifier: MIT OR Apache-2.0

use cosmic_text::BorrowedWithFontSystem;
use cosmic_text::Color;
use cosmic_text::Editor;
use cosmic_text::Shaping;
use cosmic_text::{Attrs, Buffer, Edit, Family, FontSystem, Metrics, SwashCache};
use std::{num::NonZeroU32, rc::Rc, slice};
use tiny_skia::{Paint, PixmapMut, Rect, Transform};
use winit::{
    event::{Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop},
    window::WindowBuilder,
};

fn set_buffer_text(buffer: &mut BorrowedWithFontSystem<'_, Buffer>) {
    let attrs = Attrs::new();
    let comic_attrs = attrs.clone().family(Family::Name("Comic Neue"));

    let spans: &[(&str, Attrs)] = &[
        ("Sans", attrs.clone()),
        ("Comic", comic_attrs.clone()),
        (" ComicWithSpace", comic_attrs.clone()),
    ];

    buffer.set_rich_text(
        spans.iter().map(|(text, attrs)| (*text, attrs.clone())),
        &attrs,
        Shaping::Advanced,
        None,
    );
}

fn main() {
    env_logger::init();

    let event_loop = EventLoop::new().unwrap();
    let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap());
    let context = softbuffer::Context::new(window.clone()).unwrap();
    let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
    let mut font_system = FontSystem::new();
    let mut swash_cache = SwashCache::new();

    let display_scale = window.scale_factor() as f32;
    let metrics = Metrics::new(32.0, 44.0);
    let mut editor = Editor::new(Buffer::new_empty(metrics.scale(display_scale)));
    let mut editor = editor.borrow_with(&mut font_system);
    editor.with_buffer_mut(|buffer| {
        buffer.set_size(
            Some(window.inner_size().width as f32),
            Some(window.inner_size().height as f32),
        )
    });
    editor.with_buffer_mut(set_buffer_text);

    let bg_color = tiny_skia::Color::from_rgba8(0x34, 0x34, 0x34, 0xFF);
    let font_color = Color::rgb(0xFF, 0xFF, 0xFF);
    let cursor_color = Color::rgb(0xFF, 0xFF, 0xFF);
    let selection_color = Color::rgba(0xFF, 0xFF, 0xFF, 0x33);
    let selected_text_color = Color::rgb(0xA0, 0xA0, 0xFF);

    event_loop
        .run(|event, elwt| {
            elwt.set_control_flow(ControlFlow::Wait);

            let Event::WindowEvent { window_id, event } = event else {
                return;
            };

            match event {
                WindowEvent::RedrawRequested => {
                    let (width, height) = {
                        let size = window.inner_size();
                        (size.width, size.height)
                    };

                    surface
                        .resize(
                            NonZeroU32::new(width).unwrap(),
                            NonZeroU32::new(height).unwrap(),
                        )
                        .unwrap();

                    let mut surface_buffer = surface.buffer_mut().unwrap();
                    let surface_buffer_u8 = unsafe {
                        slice::from_raw_parts_mut(
                            surface_buffer.as_mut_ptr() as *mut u8,
                            surface_buffer.len() * 4,
                        )
                    };
                    let mut pixmap =
                        PixmapMut::from_bytes(surface_buffer_u8, width, height).unwrap();
                    pixmap.fill(bg_color);

                    editor.with_buffer_mut(|buffer| {
                        buffer.set_size(Some(width as f32), Some(height as f32))
                    });

                    let mut paint = Paint {
                        anti_alias: false,
                        ..Default::default()
                    };
                    editor.shape_as_needed(true);

                    editor.draw(
                        &mut swash_cache,
                        font_color,
                        cursor_color,
                        selection_color,
                        selected_text_color,
                        |x, y, w, h, color| {
                            // Note: due to softbuffer and tiny_skia having incompatible internal color representations we swap
                            // the red and blue channels here
                            paint.set_color_rgba8(color.b(), color.g(), color.r(), color.a());
                            pixmap.fill_rect(
                                Rect::from_xywh(x as f32, y as f32, w as f32, h as f32).unwrap(),
                                &paint,
                                Transform::identity(),
                                None,
                            );
                        },
                    );

                    surface_buffer.present().unwrap();
                }
                WindowEvent::CloseRequested => {
                    //TODO: just close one window
                    elwt.exit();
                }
                _ => {}
            }
        })
        .unwrap();
}

Additonal Info

See bevyengine/bevy#22191

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions