Skip to content

Bad text rendering when the font ascent value of the main font and those of the fallback fonts differ #629

@choyunjin

Description

@choyunjin

SDL version: 3.4.10
SDL_ttf version: 3.2.2

I want to use TTF_AddFallbackFont() to use different font in Japanese characters(Hiragana and Katakana) and other characters.

Here is a part of my code written in Rust with Rust binding of SDL:

// TTF_Init();
let sdl_ttf_ctx = sdl3::ttf::init().unwrap();

// TTF_Font* font = TTF_OpenFont("path/to/font", 120.0);
let font = sdl_ttf_ctx.load_font("GenEiGothic-P-SemiBold.ttf", 120.0).unwrap(); // subset of the original font which includes only Hiragana and Katakana
let font2 = sdl_ttf_ctx.load_font("NotoSansCJK-Medium.otf", 120.0).unwrap();

// TTF_AddFallbackFont(font, font2);
unsafe {
    let result = sdl3::ttf::sys::TTF_AddFallbackFont(font.raw(), font2.raw());
    if !result {
        eprintln!("Error occured in TTF_AddFallbackFont: {}", get_error());
        return;
    }
}

// SDL_Surface* surface = TTF_RenderText_Blended(
//     font, "漢字とひらがな", 0, (SDL_Color){ 0x29, 0xbd, 0x70, 0xff }
// );
let surface = font.render("漢字とひらがな")
    .blended(Color::RGBA(0x29, 0xbd, 0x70, 0xff)).unwrap();

and this is the result:

Image

The returned value of TTF_GetFontAscent(font) and those of TTF_GetFontAscent(font2) is different, and it seems this difference is not applied to the rendered result.

The image below is the expected result:

Image

This is the entire code shows the 'expected result':

use sdl3::get_error;
use sdl3::pixels::Color;
use sdl3::event::Event;
use sdl3::keyboard::Keycode;

fn main() {
    let sdl_ctx = sdl3::init().unwrap();
    let sdl_ttf_ctx = sdl3::ttf::init().unwrap();
    let video_subsystem = sdl_ctx.video().unwrap();

    let window = video_subsystem.window("sdl3 test", 1280, 720)
        .position_centered()
        .resizable()
        .build().unwrap();

    let mut canvas = window.into_canvas();
    canvas.set_blend_mode(sdl3::render::BlendMode::Blend);
    let texture_creator = canvas.texture_creator();

    // subset of the original font which includes only Hiragana and Katakana
    let font = sdl_ttf_ctx.load_font("GenEiGothicP-SemiBold.otf", 120.0).unwrap();

    let font2 = sdl_ttf_ctx.load_font("NotoSansCJK-Medium.otf", 120.0).unwrap();

    unsafe {
        let result = sdl3::ttf::sys::TTF_AddFallbackFont(font.raw(), font2.raw());
        if !result {
            eprintln!("Error occured in TTF_AddFallbackFont: {}", get_error());
            return;
        }
    }

    canvas.set_draw_color(Color::BLACK);
    canvas.clear();

    let surface = font.render("漢字")
        .blended(Color::RGBA(0x29, 0xbd, 0x70, 255)).unwrap();
    let texture = texture_creator
        .create_texture_from_surface(&surface).unwrap();

    let texture_query = texture.query();
    let rect = sdl3::rect::Rect::new(
        0, 0, texture_query.width, texture_query.height
    );

    canvas.copy(&texture, None, rect).unwrap();

    let surface = font.render("とひらがな")
        .blended(Color::RGBA(0x29, 0xbd, 0x70, 255)).unwrap();
    let texture = texture_creator
        .create_texture_from_surface(&surface).unwrap();

    let texture_query2 = texture.query();
    let rect = sdl3::rect::Rect::new(
        texture_query.width as i32, 20, // `20` is the difference of the font ascent
        texture_query2.width, texture_query2.height
    );

    canvas.copy(&texture, None, rect).unwrap();

    canvas.present();

    let mut event_pump = sdl_ctx.event_pump().unwrap();
    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions